home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 41
/
Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso
/
-seriously_amiga-
/
programming
/
other
/
sounddt41src
/
dispatch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-04-19
|
99KB
|
4,139 lines
/*
* SoundDT41 -- A free release of the sound.datatype v41 source code
* Copyright (C) 1998/99 Stephan Rupprecht
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __MAXON__
#define CLIB_ALIB_PROTOS_H
#endif
#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <dos/var.h>
#include <dos/dostags.h>
#include <dos/rdargs.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <datatypes/soundclass.h>
#include <datatypes/soundclassext.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>
#include <libraries/iffparse.h>
#include <devices/audio.h>
#include <intuition/classes.h>
#include <intuition/gadgetclass.h>
#include <intuition/icclass.h>
#include <intuition/imageclass.h>
#include <intuition/intuitionbase.h>
#include <devices/ahi.h>
#include <gadgets/tapedeck.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>
#ifdef __GNUC__
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/iffparse.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/utility.h>
#include <proto/datatypes.h>
#include <proto/ahi.h>
#else
#include <pragma/exec_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/utility_lib.h>
#include <pragma/iffparse_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/datatypes_lib.h>
#include <pragma/ahi_lib.h>
#endif
#pragma header
#include "classbase.h"
#ifndef __MAXON__
#include "CompilerSpecific.h"
#include "BoopsiStubs.h"
#endif
#include "aiff.h"
#ifndef __MAXON__
#define IntuitionBase cb->cb_IntuitionBase
#define GfxBase cb->cb_GfxBase
#define DOSBase cb->cb_DOSBase
#define SysBase cb->cb_SysBase
#define DataTypesBase cb->cb_DataTypesBase
#define UtilityBase cb->cb_UtilityBase
#define IFFParseBase cb->cb_IFFParseBase
#else
#define REG(r,v) register __## r v
#define __regargs
#endif
#define G(x) ((struct Gadget *)(x))
#define MAX( a, b ) ((a) > (b) ? (a) : (b))
#define EXTG( x ) ((struct ExtGadget *)(x))
#ifndef ID_CHAN
#define ID_CHAN MAKE_ID( 'C', 'H', 'A', 'N' )
#endif
#ifndef ID_16SV
#define ID_16SV MAKE_ID( '1', '6', 'S', 'V' )
#endif
#ifndef ID_PAN
#define ID_PAN MAKE_ID( 'P', 'A', 'N', ' ' )
#endif
#ifndef ID_ANNO
#define ID_ANNO MAKE_ID( 'A', 'N', 'N', 'O' )
#endif
#ifndef ID_AUTH
#define ID_AUTH MAKE_ID( 'A', 'U', 'T', 'H' )
#endif
#ifndef ID_FVER
#define ID_FVER MAKE_ID( 'F', 'V', 'E', 'R' )
#endif
#ifndef ID_Copyright
#define ID_Copyright MAKE_ID( '(', 'c', ')', ' ' )
#endif
#define TEMPLATE "VOLUME/N/K,BUFFERSIZE/N/K,AHI/S,AHIMODEID/K,FAM=FORCEAHIMODE/S,AMF=AHIMIXFREQ/N/K,AIFF16/S,C=COMPRESS/S," \
"W=WIDTH/N/K,H=HEIGHT/N/K,BG=BACKGROUNDCOLOR/K,WF=WAVEFORMCOLOR/K,CP=CONTROLPANEL/T,NOGTSLIDER/S"
// MaxonC likes to use 16bit math even when 020+ optimiziation is turned on (BUG!)
#ifdef __MAXON__
#define UMult( x, y ) UMult32( (x), (y) )
#define SMult( x, y ) SMult32( (x), (y) )
#define UDiv( x, y ) UDivMod32( (x), (y) )
#define SDiv( x, y ) SDivMod32( (x), (y) )
#else
#define UMult( x, y ) ( (x) * (y) )
#define SMult( x, y ) ( (x) * (y) )
#define UDiv( x, y ) ( (x) / (y) )
#define SDiv( x, y ) ( (x) / (y) )
#endif
#define Period2Freq( x ) ( UDiv( UMult( ((struct ExecBase *)SysBase)->ex_EClockFrequency, 5L ), (x) ) )
#define Freq2Period( x ) Period2Freq( x )
#define IsStereo( x ) ( (BOOL) ( ( x ) & 1 ) )
#ifndef SHRT_MAX
#define SHRT_MAX 0x7fff
#endif
#ifdef DEBUG
#define dbug( x ) x
#else
#define dbug( x )
#endif
/****************************************************************************/
ULONG Dispatch(REG(a0,Class *cl), REG(a2,Object *o), REG(a1,Msg msg));
ULONG __regargs Sound_NEW( Class *cl, Object *o, struct opSet *ops );
ULONG __regargs Sound_GET( Class *cl, Object *o, struct opGet *ops );
ULONG __regargs Sound_SET( Class *cl, Object *o, struct opSet *ops );
ULONG __regargs Sound_UPDATE( Class *cl, Object *o, struct opUpdate *opu );
ULONG __regargs Sound_DISPOSE( Class *cl, Object *o, Msg msg );
ULONG __regargs Sound_RENDER( Class *cl, Object *o, struct gpRender *gpr );
ULONG __regargs Sound_HANDLEINPUT( Class *cl, Object *o, struct gpInput *gpi );
ULONG __regargs Sound_TRIGGER( Class *cl, Object *o, struct dtTrigger *dtt );
ULONG __regargs Sound_WRITE( Class *cl, Object *o, struct dtWrite *dtw );
ULONG __regargs Sound_LAYOUT( Class *cl, Object *o, struct gpLayout *gpl );
ULONG __regargs Sound_DOMAIN( Class *cl, Object *o, struct gpDomain *gpd );
LONG __regargs Sound_SELECT( Class *cl, Object *o, struct dtSelect *dts );
LONG __regargs Sound_CLEARSELECTED( Class *cl, Object *o, struct dtGeneral *dtg );
ULONG __regargs Sound_HITTEST( Class *cl, Object *o, struct gpHitTest *gpht );
ULONG __regargs Sound_GOINACTIVE( Class *cl, Object *o, struct gpGoInactive *gpgi );
ULONG __regargs Sound_DRAW( Class *cl, Object *o, struct dtDraw *dtd );
LONG __regargs Hex2Long( STRPTR hex );
BOOL __regargs parsetaglist( Class *cl, Object *o, struct opSet *ops );
struct Process * __regargs CreatePlayerProc( struct ClassBase *cb, struct MsgPort **mp );
void __regargs GetSoundDTPrefs( struct ClassBase *cb );
struct IBox __regargs GetAbsGadgetBox( struct IBox *domain, struct ExtGadget *g, BOOL useBounds );
ULONG __regargs DoMemberHitTest( struct IBox *domain, Object *member, struct gpHitTest *gpht );
void PlayerProc( void );
void PlayerProcAHI( void );
void __regargs makeqtab( BYTE *qtab );
unsigned __regargs strlen( STRPTR str );
ULONG propgdispatcher( REG(a0, Class *cl), REG(a2, Object *o), REG(a1, Msg msg) );
/****************************************************************************/
BYTE fibtab[] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};
UBYTE bytesPerPoint[] = { 1, 2, 2, 4 };
LONG ifferr2doserr[] =
{
0L, // EOF
0L, // EOC
DTERROR_INVALID_DATA, /* No lexical scope. */
ERROR_NO_FREE_STORE, /* Insufficient memory. */
ERROR_SEEK_ERROR, /* Stream read error. */
ERROR_SEEK_ERROR, /* Stream write error. */
ERROR_SEEK_ERROR, /* Stream seek error. */
DTERROR_INVALID_DATA, /* File is corrupt. */
DTERROR_INVALID_DATA, /* IFF syntax error. */
ERROR_OBJECT_WRONG_TYPE,/* Not an IFF file. */
ERROR_REQUIRED_ARG_MISSING,/* Required call-back hook missing. */
0xDEADDEAD /* Return to client. You should never see this ! */
};
struct DTMethod TriggerMethods[] =
{
"Play", "PLAY", STM_PLAY,
"Stop", "STOP", STM_STOP,
"Pause", "PAUSE", STM_PAUSE,
STM_DONE
};
ULONG Methods[] = {
OM_NEW,
OM_DISPOSE,
OM_SET,
OM_GET,
OM_UPDATE,
GM_RENDER,
GM_LAYOUT,
GM_DOMAIN,
GM_HITTEST,
GM_HELPTEST,
GM_GOACTIVE,
GM_HANDLEINPUT,
GM_GOINACTIVE,
DTM_TRIGGER,
DTM_WRITE,
DTM_COPY,
DTM_SELECT,
DTM_CLEARSELECTED,
DTM_PROCLAYOUT,
DTM_REMOVEDTOBJECT,
DTM_OBTAINDRAWINFO,
DTM_DRAW,
DTM_RELEASEDRAWINFO,
~0UL
};
#ifdef __MAXON__
struct Library *AHIBase = NULL;
#endif
/****************************************************************************/
ULONG Dispatch(REG(a0,Class *cl), REG(a2,Object *o), REG(a1,Msg msg))
{
struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
ULONG retval;
switch( msg->MethodID )
{
case OM_NEW:
retval = Sound_NEW( cl, o, (struct opSet *)msg );
break;
case OM_GET:
retval = Sound_GET( cl, o, (struct opGet *)msg );
break;
case OM_UPDATE:
retval = Sound_UPDATE( cl, o, (struct opUpdate *)msg );
break;
case OM_SET:
case OM_NOTIFY:
retval = Sound_SET( cl, o, (struct opSet *)msg );
break;
case OM_DISPOSE:
retval = Sound_DISPOSE( cl, o, msg );
break;
case GM_HELPTEST:
case GM_HITTEST:
retval = Sound_HITTEST( cl, o, (struct gpHitTest *) msg );
break;
case GM_GOACTIVE:
case GM_HANDLEINPUT:
retval = Sound_HANDLEINPUT( cl, o, (struct gpInput *)msg );
break;
case GM_GOINACTIVE:
retval = Sound_GOINACTIVE( cl, o, (struct gpGoInactive *) msg );
break;
case GM_DOMAIN:
retval = Sound_DOMAIN( cl, o, (struct gpDomain *)msg );
break;
case GM_LAYOUT:
case DTM_PROCLAYOUT:
retval = Sound_LAYOUT( cl, o, (struct gpLayout *)msg );
break;
case GM_RENDER:
retval = Sound_RENDER( cl, o, (struct gpRender *)msg );
break;
case DTM_TRIGGER:
retval = Sound_TRIGGER( cl, o, (struct dtTrigger *)msg );
break;
case DTM_COPY:
case DTM_WRITE:
retval = Sound_WRITE( cl, o, (struct dtWrite *)msg );
break;
case DTM_SELECT:
retval = Sound_SELECT( cl, o, (struct dtSelect *) msg );
break;
case DTM_CLEARSELECTED:
retval = Sound_CLEARSELECTED( cl, o, (struct dtGeneral *) msg );
break;
case DTM_OBTAINDRAWINFO:
{
struct InstanceData *id = INST_DATA( cl, o );
dbug( kprintf( "DTM_OBTAINDRAWINFO\n" ); )
retval = ( ( id->Screen = (struct Screen *) GetTagData( PDTA_Screen, NULL, ((struct opSet *)msg)->ops_AttrList ) ) ||
( id->DrawInfo = (struct DrawInfo *) GetTagData( GA_DrawInfo, NULL, ((struct opSet *)msg)->ops_AttrList ) ) );
}
break;
case DTM_DRAW:
retval = Sound_DRAW( cl, o, (struct dtDraw *) msg );
break;
case DTM_RELEASEDRAWINFO:
dbug( kprintf( "DTM_RELEASEDRAWINFO\n" ); )
retval = 0L;
break;
case DTM_REMOVEDTOBJECT:
{
struct InstanceData *id = INST_DATA( cl, o );
/* prevent other tasks (cursor- or playertask) from reading this */
dbug( kprintf( "DTM_REMOVEDTOBJECT\n" ); )
ObtainSemaphore( &id->Lock );
id->Window = (struct Window *)
id->Requester = NULL;
ReleaseSemaphore( &id->Lock );
if( id->ColorMap )
{
ReleasePen( id->ColorMap, id->BackgroundPen );
ReleasePen( id->ColorMap, id->WaveformPen );
}
}
default:
dbug( kprintf("METHOD: %08lx\n", msg->MethodID); )
retval = (ULONG) DoSuperMethodA(cl, o, msg);
}
return(retval);
}
/****************************************************************************/
#ifdef __MAXON__
ULONG NotifyAttrs( Object *o, struct GadgetInfo *ginfo, ULONG flags, Tag tag1, ... )
{
struct opUpdate opu;
opu . MethodID = OM_NOTIFY;
opu . opu_AttrList = (struct TagItem *)(&tag1);
opu . opu_GInfo = ginfo;
opu . opu_Flags = flags;
return( DoMethodA( o, (Msg)(&opu) ) );
}
#endif
/****************************************************************************/
LONG SendObjectMsg( struct InstanceData *id, ULONG Command, APTR Data )
{
#ifndef __MAXON__
#undef SysBase
struct Library *SysBase = (*(struct Library **)4L);
#endif
struct ObjectMsg *msg;
if( msg = AllocVec( sizeof( *msg ), MEMF_PUBLIC|MEMF_CLEAR ) )
{
msg->Command = Command;
msg->Data = Data;
PutMsg( id->PlayerPort, &msg->Message );
}
else
{
dbug( kprintf( "No memory to send objmsg\n" ); )
}
return( (LONG) (msg!=NULL) );/*
struct MsgPort *replyport;
LONG err = ERROR_NO_FREE_STORE;
#ifdef NO_SIGB_SINGLE_PORT
replyport = CreateMsgPort();
if( msg = (struct ObjectMsg *) CreateIORequest( replyport, sizeof( *msg ) ) )
{
msg->Command = Command;
msg->Data = Data;
PutMsg( id->PlayerPort, &msg->Message );
WaitPort( replyport );
GetMsg( replyport );
//err = msg->ErrorCode;
DeleteIORequest( (struct IORequest *) msg );
}
DeleteMsgPort( replyport );
return TRUE;
#else
if( replyport = AllocVec( sizeof( *replyport ) + sizeof( *msg ), MEMF_PUBLIC|MEMF_CLEAR ) )
{
replyport->mp_SigTask = FindTask( NULL );
replyport->mp_SigBit = SIGB_SINGLE;
NewList( &replyport->mp_MsgList );
msg = (struct ObjectMsg *) (replyport+1);
msg->Message.mn_ReplyPort = replyport;
msg->Command = Command;
msg->Data = Data;
SetSignal( 0L, SIGF_SINGLE );
PutMsg( id->PlayerPort, &msg->Message );
WaitPort( replyport );
GetMsg( replyport );
err = msg->ErrorCode;
FreeVec( replyport );
return TRUE;
}
#endif
return NULL;
*/
#ifndef __MAXON__
#define SysBase cb->cb_SysBase
#endif
}
/****************************************************************************/
LONG __regargs Sound_CLEARSELECTED( Class *cl, Object *o, struct dtGeneral *dtg )
{
struct RastPort *rp;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
LONG retval = 0L;
dbug( kprintf( "DTM_CLEARSELECTED\n"); )
/* 'magic' nothing selected value */
id->MinX =
id->MaxX = ~0;
id->StartSample =
id->EndSample = ~0L;
if( rp = ObtainGIRPort( dtg->dtg_GInfo ) )
{
DoMethod( o, GM_RENDER, (ULONG) dtg->dtg_GInfo, (ULONG) rp, (ULONG) GREDRAW_REDRAW );
ReleaseGIRPort( rp );
}
((struct DTSpecialInfo *)(G( o ) -> SpecialInfo)) -> si_Flags &= ~DTSIF_HIGHLIGHT;
return retval;
}
/****************************************************************************/
LONG __regargs Sound_SELECT( Class *cl, Object *o, struct dtSelect *dts )
{
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
WORD minX = id->MinX, maxX = id->MaxX, oldx,
x = G(o)->LeftEdge, w = G(o)->Width;
ULONG samplelength = id->SampleLength,
startSample = ~0L, endSample = ~0L;
LONG dy = samplelength, dx, error, add, sub, step = 1L, i,
retval = 0L;
dbug( kprintf("DTM_SELECT\n"); )
if( minX > maxX )
{
maxX = minX;
minX = id->MaxX;
}
/* get abs xpos/width */
if( G(o)->Flags & GFLG_RELWIDTH )
{
w += dts->dts_GInfo->gi_Domain.Width;
}
if( G(o)->Flags & GFLG_RELRIGHT )
{
x += dts->dts_GInfo->gi_Domain.Left;
}
oldx = x+=4; w-=8;
dx = w;
/* a big sample */
if( samplelength >> 17 )
{
dy >>= 7;
step = 128;
}
/* get first and last sample of the marked area by
** comparing the coordinates */
if( samplelength <= w )
{
LONG c = 0L;
error = dy-2*dx-1;
sub = 2*(dx+1); add = 2*(dy+1);
for( i = w; i; i-- )
{
if( x >= minX && startSample == ~0L )
{
startSample = c;
}
else if( x++ >= maxX )
{
endSample = c;
break;
}
if( error > 0 )
{
c += step;
error -= sub;
}
error += add;
}
}
else
{
error = dx-2*dy-1;
sub = 2*(dy+1); add = 2*(dx+1);
for( i = 0; i < samplelength; i+=step )
{
if( error > 0 )
{
if( x >= minX && startSample == ~0L )
{
startSample = i;
}
else if( x++ >= maxX )
{
endSample = i;
break;
}
error -= sub;
}
error += add;
}
}
/* some corrections */
if( endSample == ~0L )
{
endSample = samplelength;
}
if( minX == oldx)
{
startSample = 0L;
}
id->StartSample = startSample;
id->EndSample = endSample;
dbug( kprintf( "%ld, %ld\n", startSample, endSample ); )
return retval;
}
/****************************************************************************/
void __regargs GetSoundDTPrefs( struct ClassBase *cb )
{
TEXT buf[256];
LONG len;
dbug( kprintf( "GetSoundDTPrefs\n" ); )
ObtainSemaphore( &cb->cb_LibLock );
/* set default settings */
dbug( kprintf( "Setting default values\n" ); )
cb->cb_AHI = FALSE;
cb->cb_AHIModeID = AHI_DEFAULT_ID;
cb->cb_ForceAHIMode = FALSE;
cb->cb_AHIMixFrequency = AHI_DEFAULT_FREQ;
cb->cb_Compress = FALSE;
cb->cb_AIFF = FALSE;
cb->cb_NomWidth = 160;
cb->cb_NomHeight = 100;
cb->cb_BgCol[0] =
cb->cb_BgCol[1] =
cb->cb_BgCol[2] = 0;
cb->cb_WfCol[0] = 35 << 24L;
cb->cb_WfCol[1] = 204 << 24L;
cb->cb_WfCol[2] = 23 << 24L;
cb->cb_BufferSize = 65536L;
cb->cb_Volume = 64L;
cb->cb_ControlPanel = FALSE;
cb->cb_NoGTSlider = FALSE;
if( ( len = GetVar( "datatypes/sounddt41.prefs", buf, sizeof( buf )-1, GVF_GLOBAL_ONLY ) ) > 0 )
{
struct RDArgs *rdargs;
dbug( kprintf( "Prefs: %s\n", buf ); )
if( rdargs = AllocDosObject( DOS_RDARGS, NULL ) )
{
struct RDArgs *freeargs;
struct {
LONG *volume;
LONG *buffersize;
LONG ahi;
STRPTR ahimodeid;
LONG forceahimode;
LONG *mixfreq;
LONG aiff;
LONG compress;
LONG *width, *height;
STRPTR bg, wf;
LONG cp;
LONG nogtsl;
} args = { };
/* prepare rdargs */
buf[len++] = '\n';
rdargs->RDA_Source.CS_Buffer = buf;
rdargs->RDA_Source.CS_Length = len;
rdargs->RDA_Flags = RDAF_NOPROMPT;
if( freeargs = ReadArgs( TEMPLATE, (LONG *)&args, rdargs ) )
{
dbug( kprintf( "List of options:\n" ); )
if( args.ahi )
{
cb->cb_AHI = TRUE;
dbug( kprintf( "AHI\n" ); )
}
if( args.ahimodeid )
{
cb->cb_AHIModeID = Hex2Long( args.ahimodeid );
dbug( kprintf( "AHIMODEID = %lx\n", cb->cb_AHIModeID ); )
}
if( args.forceahimode )
{
cb->cb_ForceAHIMode = TRUE;
dbug( kprintf( "FAM\n" ); )
}
if( args.mixfreq )
{
cb->cb_AHIMixFrequency = *args.mixfreq;
dbug( kprintf( "AHIMIXFREQ = %ld\n", *args.mixfreq ); )
}
if( args.aiff )
{
cb->cb_AIFF = TRUE;
dbug( kprintf( "AIFF16\n" ); )
}
if( args.compress )
{
cb->cb_Compress = TRUE;
dbug( kprintf( "COMPRESS\n" ); )
}
if( args.width )
{
cb->cb_NomWidth = *args.width;
dbug( kprintf( "WIDTH = %ld\n", *args.width ); )
}
if( args.height )
{
cb->cb_NomHeight = *args.height;
dbug( kprintf( "HEIGHT = %ld\n", *args.height ); )
}
if( args.wf )
{
LONG num = Hex2Long( args.wf );
cb->cb_WfCol[0] = (num>>16L)<<24;
cb->cb_WfCol[1] = (num>>8L)<<24L;
cb->cb_WfCol[2] = (num)<<24L;
dbug( kprintf( "WFCOL = %08lx\n", num ); )
}
if( args.bg )
{
LONG num = Hex2Long( args.bg );
cb->cb_BgCol[0] = (num>>16L)<<24L;
cb->cb_BgCol[1] = (num>>8L)<<24L;
cb->cb_BgCol[2] = (num)<<24L;
dbug( kprintf( "BGCOL = %08lx\n", num ); )
}
if( args.buffersize )
{
LONG bufsize = *args.buffersize;
if( bufsize > 1023 && bufsize < 131073 )
{
cb->cb_BufferSize = bufsize;
}
dbug( kprintf( "BUFFERSZ = %ld\n", bufsize ); )
}
if( args.cp )
{
cb->cb_ControlPanel = TRUE;
dbug( kprintf( "CP=YES\n" ); )
}
else
{
cb->cb_ControlPanel = FALSE;
dbug( kprintf( "CP=NO\n" ); )
}
if( args.volume )
{
cb->cb_Volume = *args.volume;
dbug( kprintf( "VOLUME = %ld\n", *args.volume ); )
}
if( args.nogtsl )
{
cb->cb_NoGTSlider = TRUE;
dbug( kprintf( "NOGTSLIDER\n" ); )
}
FreeArgs( freeargs );
}
else
{
extern TEXT LibName[];
struct EasyStruct es = { sizeof(struct EasyStruct), NULL, LibName, buf, "Okay" };
if( Fault( IoErr(), "Error in prefs file", buf, sizeof( buf ) ) )
{
dbug( kprintf( "Prefserr: %s\n" , buf ); )
EasyRequestArgs( NULL, &es, NULL, NULL );
}
}
FreeDosObject( DOS_RDARGS, rdargs );
}
else
{
dbug( kprintf( "AllocDosObject() failed\n" ); )
}
}
else
{
dbug( kprintf( "GetVar failed\n" ); )
}
ReleaseSemaphore( &cb->cb_LibLock );
}
/****************************************************************************/
LONG hex2long(STRPTR s)
{ ULONG a;
BYTE c;
if (s && (c=*s++) && (c=='$' || (c == '0' && *s++ == 'x'))) {
a=0;
while ((c=*s++)) {
if (c>'9')
c&=0x5f;
if ((c-='0')<0 || (c>9 && (c-=7)>15))
return 0;
a<<=4,a|=c;
}
return a;
}
return 0;
}
/****************************************************************************/
void CreateTapeDeck( struct ClassBase *cb, struct InstanceData *id, Object *o )
{
#ifdef __MAXON__
extern struct Library *TapeDeckBase;
#else
#define TapeDeckBase cb->cb_TapeDeckBase
#endif
ULONG cp;
dbug( kprintf( "Creating panel\n" ); )
GetDTAttrs( o, DTA_ControlPanel, (ULONG) &cp, TAG_DONE );
if( TapeDeckBase && cp )
{
STATIC struct TagItem prop2vol[] = { PGA_Top, SDTA_Volume, TAG_END };
ObtainSemaphoreShared( &cb->cb_LibLock );
if( id->VolumeSlider = NewObject( NULL, PROPGCLASS,
PGA_Top, id->Volume,
PGA_Visible, 1L,
PGA_Total, 64L,
PGA_Freedom, FREEHORIZ,
PGA_NewLook, cb->cb_NoGTSlider,
! cb->cb_NoGTSlider ? PGA_Borderless : TAG_IGNORE, TRUE,
ICA_TARGET, (ULONG) o,
ICA_MAP, (ULONG) prop2vol,
TAG_DONE ) )
{
if( id->TapeDeckGadget = NewObject( NULL, "tapedeck.gadget",
TDECK_Tape, TRUE,
TAG_DONE ) )
{
ReleaseSemaphore( &cb->cb_LibLock );
return;
}
DisposeObject( id->VolumeSlider );
id->VolumeSlider = NULL;
}
ReleaseSemaphore( &cb->cb_LibLock );
}
else
{
dbug( kprintf( "Failed or turned off\n" ); )
}
id->ControlPanel = FALSE;
}
/****************************************************************************/
ULONG __regargs Sound_NEW( Class *cl, Object *o, struct opSet *ops )
{
struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
struct TagItem ti[6];
dbug( kprintf( "OM_NEW\n" ); )
GetSoundDTPrefs( cb );
ObtainSemaphoreShared( &cb->cb_LibLock );
ti[0].ti_Tag = DTA_NominalHoriz;
ti[0].ti_Data = cb->cb_NomWidth;
ti[1].ti_Tag = DTA_NominalVert;
ti[1].ti_Data = cb->cb_NomHeight;
ti[2].ti_Tag = DTA_VertUnit;
ti[2].ti_Data = 1L;
ti[3].ti_Tag = DTA_HorizUnit;
ti[3].ti_Data = 1L;
ti[4].ti_Tag = DTA_ControlPanel;
ti[4].ti_Data = cb->cb_ControlPanel;
ti[5].ti_Tag = TAG_MORE;
ti[5].ti_Data = (ULONG) ops->ops_AttrList;
ReleaseSemaphore( &cb->cb_LibLock );
ops->ops_AttrList = ti;
if( o = (Object *) DoSuperMethodA( cl, o, (Msg) ops ) )
{
struct InstanceData *id = INST_DATA( cl, o );
struct ObjectMsg *msg;
struct MsgPort *replyport;
id->Volume = cb->cb_Volume;
id->Frequency = Period2Freq( 394 );
id->Cycles = 1;
id->SignalBit = -1;
// id->SampleType = SDTST_M8S;
id->Panning = 0x8000;
/* 'magic' nothing selected value */
id->MinX =
id->MaxX = ~0L;
id->StartSample =
id->EndSample = ~0L;
id->TapeDeckHeight = 15L; // tapedeck.gadget is currently limited to 15 pixels
id->BackgroundPen =
id->WaveformPen = -1;
id->ClassBase = cb;
InitSemaphore( &id->Lock );
/* create process */
replyport = CreateMsgPort();
if( msg = (struct ObjectMsg *) CreateIORequest( replyport, sizeof( *msg ) ) )
{
extern UBYTE LibName[];
ObtainSemaphoreShared( &cb->cb_LibLock );
if( id->PlayerProc = CreateNewProcTags(
NP_Name, (ULONG) LibName,
NP_Entry, (ULONG) (cb->cb_AHI) ? (ULONG) PlayerProcAHI : (ULONG) PlayerProc,
NP_Priority, 19L,
TAG_DONE ) )
{
msg->Data = (APTR) id;
msg->Command = COMMAND_INIT;
PutMsg( &id->PlayerProc->pr_MsgPort, &msg->Message );
WaitPort( replyport );
GetMsg( replyport );
if( msg->Data )
{
id->PlayerPort = (struct MsgPort *) msg->Data;
}
else
{
id->PlayerProc = NULL;
}
}
ReleaseSemaphore( &cb->cb_LibLock );
DeleteIORequest( (struct IORequest *) msg );
if( id->PlayerProc )
{
parsetaglist( cl, o, ops );
CreateTapeDeck( cb, id, o );
}
else
{
CoerceMethod( cl, o, OM_DISPOSE );
o = NULL;
}
}
else
{
dbug( kprintf( "No memory for ioreq or msgport\n" ); )
}
DeleteMsgPort( replyport );
}
else
{
dbug( kprintf( "OM_NEW failed\n" ); )
}
ops->ops_AttrList = (struct TagItem *) ti[5].ti_Data;
dbug( if( !o ) kprintf("Object creation failed\n"); )
return( (ULONG) o );
}
/****************************************************************************/
void __regargs SetVSlider( struct ClassBase *cb, struct InstanceData *id )
{
/* this function works aroung a "spilled register" error */
if( id->ControlPanel )
{
ULONG top;
GetAttr( PGA_Top, id->VolumeSlider, &top );
if( top != id->Volume ) // avoid loops
{
SetGadgetAttrs( id->VolumeSlider, id->Window, id->Requester,
PGA_Top, id->Volume, TAG_DONE );
}
}
}
/****************************************************************************/
BOOL __regargs parsetaglist( Class *cl, Object *o, struct opSet *ops )
{
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
struct TagItem *ti, *tstate = ops->ops_AttrList;
struct InstanceData *id = INST_DATA( cl, o );
BOOL change = FALSE, newSample = FALSE;
ObtainSemaphore( &id->Lock );
while( ti = NextTagItem( &tstate ) )
{
ULONG data = ti->ti_Data;
switch( ti->ti_Tag )
{
case SDTA_VoiceHeader:
id->VoiceHeader = *(struct VoiceHeader *) data;
dbug( kprintf("SDTA_VoiceHeader\n"); )
break;
case SDTA_Sample:
id->Sample = (BYTE *) data;
dbug( kprintf("SDTA_Sample = %08lx\n", data); )
newSample = TRUE;
break;
case SDTA_SampleLength:
id->SampleLength = data;
dbug( kprintf("SDTA_SampleLength = %ld\n", data); )
break;
case SDTA_Period:
id->Frequency = (UWORD) Period2Freq( data );
change = TRUE;
dbug( kprintf("SDTA_Period = %ld (%ldHz)\n", data, Period2Freq(data) ); )
break;
case SDTA_Volume:
id->Volume = (UWORD) data;
change = TRUE;
SetVSlider( cb, id );
dbug( kprintf("SDTA_Volume = %ld\n", data); )
break;
case SDTA_Cycles:
id->Cycles = (UWORD) data;
dbug( kprintf("SDTA_Cycles = %ld\n", data); )
break;
case SDTA_SignalTask:
id->SignalTask = (struct Task *) data;
dbug( kprintf("SDTA_SignalTask = %08lx\n", data); )
break;
case SDTA_SignalBit:
id->SignalBit = (BYTE) data;
dbug( kprintf("SDTA_SignalBit = %ld\n", data); )
break;
case SDTA_Continuous:
id->Continuous = (BOOL) data;
dbug( kprintf("SDTA_Continuous = %ld\n", data); )
break;
case SDTA_SampleType:
id->SampleType = data;
dbug( kprintf("SDTA_SampleType = %ld\n", data ); )
break;
case SDTA_Panning:
id->Panning = data;
change = TRUE;
dbug( kprintf("SDTA_Panning = %05lx\n", data ); )
break;
case SDTA_Frequency:
id->Frequency = data;
change = TRUE;
dbug( kprintf("SDTA_Frequency =%ld\n", data); )
break;
case DTA_ControlPanel:
if( data != id->ControlPanel )
{
id->ForceRefresh = TRUE;
}
id->ControlPanel = (BOOL) data;
dbug( kprintf("DTA_ControlPanel =%ld\n", data); )
break;
case DTA_Immediate:
if( ! ( id->Immediate = data ) )
{
CoerceMethod( cl, o, DTM_TRIGGER, NULL, STM_STOP, NULL );
}
else
{
newSample = ( id->Sample != NULL );
id->DelayedImmed = TRUE;
}
break;
case DTA_Repeat:
id->Repeat = (BOOL) data;
break;
default:
dbug( kprintf("Attr: %08lx\n", ti->ti_Tag); )
}
}
ReleaseSemaphore( &id->Lock );
/*- inform sound object handler about that change -*/
if( change && id->PlayerProc )
{
SendObjectMsg( id, COMMAND_PERVOL, NULL );
}
if( newSample )
{
/* continuous stream of data ? */
if( id->Continuous )
{
/* inform player process that we got a new buffer */
SendObjectMsg( id, COMMAND_NEXT_BUFFER, NULL );
}
else if( id->Immediate && id->DelayedImmed )
{
id->DelayedImmed = FALSE;
CoerceMethod( cl, o, DTM_TRIGGER, NULL, STM_PLAY, NULL );
}
}
return( change );
}
/****************************************************************************/
ULONG __regargs Sound_GET( Class *cl, Object *o, struct opGet *opg )
{
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
ULONG retval = TRUE, data;
dbug( kprintf("OM_GET\n"); )
switch( opg->opg_AttrID )
{
case SDTA_VoiceHeader:
data = (ULONG) &id->VoiceHeader;
dbug( kprintf("SDTA_VoiceHeader\n"); )
break;
case SDTA_Sample:
data = (ULONG) id->Sample;
dbug( kprintf("SDTA_Sample\n"); )
break;
case SDTA_SampleLength:
data = id->SampleLength;
dbug( kprintf("SDTA_SampleLength\n"); )
break;
case SDTA_Period:
data = (ULONG) Freq2Period( id->Frequency );
dbug( kprintf("SDTA_Period\n"); )
break;
case SDTA_Volume:
data = (ULONG) id->Volume;
dbug( kprintf("SDTA_Volume\n"); )
break;
case SDTA_Cycles:
data = (ULONG) id->Cycles;
dbug( kprintf("SDTA_Cycles\n"); )
break;
case SDTA_SignalTask:
data = (ULONG) id->SignalTask;
dbug( kprintf("SDTA_SignalTask\n"); )
break;
case SDTA_SignalBit:
data = (ULONG) id->SignalBit;
dbug( kprintf("SDTA_SignalBit\n"); )
break;
case SDTA_Continuous:
data = (ULONG) id->Continuous;
dbug( kprintf("SDTA_Continuous\n"); )
break;
case SDTA_Panning:
data = id->Panning;
dbug( kprintf("SDTA_Panning\n"); )
break;
case SDTA_SampleType:
data = id->SampleType;
dbug( kprintf("SDTA_SampleType\n"); )
break;
case SDTA_Frequency:
data = id->Frequency;
dbug( kprintf("SDTA_Frequency\n"); )
break;
case DTA_TriggerMethods:
data = (ULONG) TriggerMethods;
dbug( kprintf("SDTA_TriggerMethods\n"); )
break;
case DTA_ControlPanel:
data = (ULONG) id->ControlPanel;
dbug( kprintf("DTA_ControlPanel\n"); )
break;
case DTA_Repeat:
data = (ULONG) id->Repeat;
break;
case DTA_Immediate:
data = (ULONG) id->Immediate;
break;
case DTA_Methods:
{
dbug( kprintf( "DTA_Methods\n"); )
#ifndef __GNUC__
ObtainSemaphore( &cb->cb_LibLock );
/* first request of DTA_Methods ? */
if( ! ( data = (ULONG) cb->cb_Methods ) )
{
ULONG cntSuper, cntMethods, *superMethods, *newMethods;
/* create Methods array */
DoSuperMethod( cl, o, OM_GET, DTA_Methods, (ULONG) &superMethods );
for( cntSuper = 0; superMethods[ cntSuper ] != ~0L; cntSuper++ ) {}
for( cntMethods = 0; Methods[ cntMethods ] != ~0L; cntMethods++ ) {}
cb->cb_Methods = // For any reasons, GNUC seems to have problems here !
newMethods = (ULONG *) AllocVec( ( cntSuper+cntMethods+1UL ) * sizeof( ULONG ), MEMF_PUBLIC );
if( data = (ULONG) newMethods )
{
ULONG num = 0L;
CopyMem( superMethods, newMethods, sizeof( ULONG ) * cntSuper );
newMethods += cntSuper;
for( num = 0; num < cntMethods; num++ )
{
ULONG i, method = Methods[ num ];
for( i = 0; i < cntSuper; i++ )
{
if( superMethods[ i ] == method )
{
break;
}
}
if( i == cntSuper )
{
*newMethods++ = method;
}
}
*newMethods = ~0L;
}
else
{
data = (ULONG) Methods;
}
}
ReleaseSemaphore( &cb->cb_LibLock );
#else
ObtainSemaphore( &cb->cb_LibLock );
if( ! ( data = (ULONG) cb->cb_Methods ) )
{
if( DataTypesBase->lib_Version >= 45L )
{
ULONG *superMethods = NULL;
DoSuperMethod( cl, o, OM_GET, DTA_Methods, (ULONG) &superMethods );
data = (ULONG) ( cb->cb_Methods = CopyDTMethods( superMethods, Methods, NULL ) );
dbug( kprintf( "CopyDTMethods returned %08lx\n", data ); )
}
}
if( ! data )
{
data = (ULONG) Methods;
}
ReleaseSemaphore (&cb->cb_LibLock );
#endif
}
break;
default:
retval = FALSE;
dbug( kprintf("Attr: %08lx\n", opg->opg_AttrID); )
}
if( retval )
{
*opg->opg_Storage = data;
}
else
{
retval = DoSuperMethodA( cl, o, (Msg) opg );
dbug( kprintf("SuperAttr: %08lx, %08lx\n", opg->opg_AttrID, *opg->opg_Storage); )
}
return( retval );
}
/****************************************************************************/
ULONG __regargs Sound_SET( Class *cl, Object *o, struct opSet *ops )
{
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
ULONG retval;
dbug( kprintf("OM_SET\n"); )
retval = DoSuperMethodA( cl, o, (Msg) ops );
parsetaglist( cl, o, ops );
if( retval || ( ( id->ForceRefresh ) && ( id->Gadget ) ) )
{
struct RastPort *rp;
if( rp = ObtainGIRPort( ops->ops_GInfo ) )
{
DoMethod( o, GM_RENDER, (ULONG) ops->ops_GInfo, (ULONG) rp, GREDRAW_REDRAW );
ReleaseGIRPort( rp );
id->ForceRefresh = FALSE;
}
}
return( retval );
}
/****************************************************************************/
ULONG __regargs Sound_UPDATE( Class *cl, Object *o, struct opUpdate *opu )
{
struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
dbug( kprintf("OM_UPDATE\n"); )
return( DoMethod( o, ICM_CHECKLOOP ) ? FALSE : Sound_SET( cl, o, (struct opSet *) opu ) );
}
/****************************************************************************/
ULONG __regargs Sound_DISPOSE( Class *cl, Object *o, Msg msg )
{
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct SignalSemaphore *lock = &((struct DTSpecialInfo *)G( o )->SpecialInfo)->si_Lock;
dbug( kprintf("OM_DISPOSE\n"); )
/* free playerproc stuff */
if( id->PlayerProc )
{
struct MsgPort *replyport;
struct ObjectMsg *msg;
while( ! ( replyport = CreateMsgPort() ) )
{
Delay( 25L );
}
while( ! ( msg = (struct ObjectMsg *) CreateIORequest( replyport, sizeof( *msg ) ) ) )
{
Delay( 25L );
}
msg->Command = COMMAND_EXIT;
PutMsg( id->PlayerPort, &msg->Message );
WaitPort( replyport );
GetMsg( replyport );
DeleteIORequest( (struct IORequest *) msg );
DeleteMsgPort( replyport );
}
/* free controls */
dbug( kprintf( "freeing controls\n" ); )
DisposeObject( id->TapeDeckGadget );
DisposeObject( id->VolumeSlider );
/* free sample memory, obtain semaphore in case that there's a write in progess */
dbug( kprintf( "releasing memory\n" ); )
ObtainSemaphore( lock );
FreeVec( id->Sample );
ReleaseSemaphore( lock );
return( DoSuperMethodA( cl, o, msg ) );
}
/****************************************************************************/
ULONG __regargs Sound_DOMAIN( Class *cl, Object *o, struct gpDomain *gpd )
{
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct IBox *gbox = &gpd->gpd_Domain;
dbug( kprintf("GDOMAIN\n"); )
*gbox = GetAbsGadgetBox( &gpd->gpd_GInfo->gi_Domain, EXTG( o ), FALSE );
switch( gpd->gpd_Which )
{
case GDOMAIN_MINIMUM:
gbox->Width = 32;
gbox->Height = id->TapeDeckHeight + 10;
break;
case GDOMAIN_NOMINAL:
ObtainSemaphoreShared( &cb->cb_LibLock );
gbox->Width = cb->cb_NomWidth;
gbox->Height = cb->cb_NomHeight;
ReleaseSemaphore( &cb->cb_LibLock );
break;
case GDOMAIN_MAXIMUM:
gbox->Width =
gbox->Height = SHRT_MAX;
break;
}
return TRUE;
}
/****************************************************************************/
ULONG __regargs Sound_LAYOUT( Class *cl, Object *o, struct gpLayout *gpl )
{
struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct DTSpecialInfo *si = (struct DTSpecialInfo *)(G( o ) -> SpecialInfo);
struct GadgetInfo *gi = gpl->gpl_GInfo;
struct IBox *domain = NULL;
STRPTR name = NULL;
ULONG retval;
dbug( kprintf( "GM_LAYOUT\n" ); )
retval = DoSuperMethodA( cl, o, (Msg) gpl );
si->si_Flags |= DTSIF_LAYOUT;
ObtainSemaphore( &si->si_Lock );
NotifyAttrs( o, gi, 0L,
GA_ID, G( o )->GadgetID,
DTA_Busy, TRUE,
TAG_DONE );
if( GetDTAttrs( o,
DTA_ObjName, (ULONG) &name,
DTA_Domain, (ULONG) &domain,
TAG_DONE ) == 2L )
{
ULONG vunit = si->si_VertUnit,
hunit = si->si_HorizUnit,
totalw = si->si_TotHoriz,
totalh = si->si_TotVert;
si->si_VertUnit = vunit;
si->si_VisVert = domain->Height / vunit;
si->si_TotVert = totalh;
si->si_HorizUnit = hunit;
si->si_VisHoriz = domain->Width / hunit;
si->si_TotHoriz = totalw;
if( ! name )
{
if( ! GetDTAttrs( o, DTA_Name, (ULONG) &name, TAG_DONE ) || ! name )
{
name = "Untitled";
}
else
{
name = FilePart( name );
}
}
if( gpl->gpl_Initial )
{
ObtainSemaphore( &id->Lock );
id->Window = gi->gi_Window;
id->Requester = gi->gi_Requester;
id->Gadget = (struct Gadget *) o;
ReleaseSemaphore( &id->Lock );
/* obtain pens */
id->ColorMap = gi->gi_Screen->ViewPort.ColorMap;
ObtainSemaphoreShared( &cb->cb_LibLock );
id->BackgroundPen = ObtainBestPenA( id->ColorMap,
cb->cb_BgCol[0], cb->cb_BgCol[1], cb->cb_BgCol[2], NULL );
id->WaveformPen = ObtainBestPenA( id->ColorMap,
cb->cb_WfCol[0], cb->cb_WfCol[1], cb->cb_WfCol[2], NULL );
ReleaseSemaphore( &cb->cb_LibLock );
}
if( id->TapeDeckGadget )
{
struct gpLayout member_gpl;
struct TagItem ti[] = {
GA_Left, domain->Left,
GA_Top, domain->Top + domain->Height - id->TapeDeckHeight,
GA_Width, 201,
GA_Height, id->TapeDeckHeight,
TAG_DONE
};
if( ( gpl->gpl_Initial ) && ( G( o )->GadgetType & GTYP_REQGADGET ) )
{
id->TapeDeckGadget->GadgetType |= GTYP_REQGADGET;
id->VolumeSlider->GadgetType |= GTYP_REQGADGET;
}
ObtainSemaphoreShared( &cb->cb_LibLock );
member_gpl = *gpl;
member_gpl.MethodID = GM_LAYOUT;
SetAttrsA( id->TapeDeckGadget, ti );
DoMethodA( (Object *) id->TapeDeckGadget, (Msg) &member_gpl );
ti[0].ti_Data += 205;
ti[2].ti_Data = domain->Width - 205;
if( ! cb->cb_NoGTSlider )
{
ti[0].ti_Data += 4;
ti[1].ti_Data += 2;
ti[2].ti_Data -= 8;
ti[3].ti_Data -= 4;
}
SetAttrsA( id->VolumeSlider, ti );
DoMethodA( (Object *) id->VolumeSlider, (Msg) &member_gpl );
ReleaseSemaphore( &cb->cb_LibLock );
}
NotifyAttrs( o, gi, 0L,
GA_ID, G(o)->GadgetID,
DTA_VisibleVert, si->si_VisVert,
DTA_TotalVert, totalh,
DTA_VertUnit, vunit,
DTA_VisibleHoriz, si->si_VisHoriz,
DTA_TotalHoriz, totalw,
DTA_HorizUnit, hunit,
DTA_Title, (ULONG) name,
DTA_Busy, FALSE,
DTA_Sync, TRUE,
TAG_DONE );
}
ReleaseSemaphore( &si->si_Lock );
si->si_Flags &= ~DTSIF_LAYOUT;
return retval + si->si_TotVert;
}
/****************************************************************************/
void __regargs DrawWaveform( struct ClassBase *cb, struct RastPort *rp, struct InstanceData *id, UWORD x, UWORD y, UWORD w, UWORD h )
{
ULONG sampleStart = id->StartSample, sampleEnd = id->EndSample;
LONG samplelength = id->SampleLength, error, dx = w, dy = samplelength, sub, add, i,
step = 1L, k=0L, oldx=x, shift = ( id->SampleType >= SDTST_M16S ? 1 : 0 );
BOOL stereo = IsStereo( id->SampleType );
WORD minX = ~0, maxX = ~0, oldy = y, oldh = h;
/* scaling limit is 25500% */
if( w > (samplelength<<8) )
{
return;
}
/* a big sample, speed up rendering */
if( samplelength >> 17 )
{
dy >>= 7;
step = 128;
}
/* adjust ypos and height for stereo sample */
if( stereo )
{
h /= 2;
y += h/2;
shift++;
}
else
{
y+= h/2;
}
for( k = 0; k < (stereo?2:1); k++ )
{
BYTE *sample = &id->Sample[ k ];
if( k && id->SampleType == SDTST_S16S )
{
sample++;
}
Move( rp, x, y );
if( samplelength <= w )
{
LONG c = 0L;
error = dy-2*dx-1;
sub = 2*(dx+1); add = 2*(dy+1);
for( i = 0; i < w; i++ )
{
/* get minX and maxX for highlighting */
if( sampleStart != ~0L )
{
if( i >= sampleStart && minX == ~0 )
{
minX = x;
}
else if( i >= sampleEnd && maxX == ~0 )
{
maxX = x;
sampleStart = ~0L; // speed up
}
}
Draw( rp, x++, y + ( SMult( sample[ c << shift ], h ) >> 8 ) );
if( error > 0 )
{
c += step;
error -= sub;
}
error += add;
}
}
else
{
error = dx-2*dy-1;
sub = 2*(dy+1); add = 2*(dx+1);
for( i = 0; i < samplelength; i+=step )
{
if( error > 0 )
{
/* get minX and maxX for highlighting */
if( sampleStart != ~0L )
{
if( i >= sampleStart && minX == ~0 )
{
minX = x;
}
else if( i >= sampleEnd && maxX == ~0 )
{
maxX = x;
sampleStart = ~0L; // speed up
}
}
Draw( rp, x++, y + ( SMult( sample[ i << shift ], h ) >> 8 ) );
error -= sub;
}
error += add;
}
}
y += h;
x = oldx;
}
/* something marked ? */
if( minX != ~0 )
{
if( maxX == ~0 )
{
maxX = oldx+w-1;
}
SetDrMd( rp, COMPLEMENT );
RectFill( rp, minX, oldy, maxX, oldy+oldh-1 );
/* fix tapedeck.gadget bug (?) */
SetDrMd( rp, JAM1 );
}
}
/****************************************************************************/
ULONG __regargs Sound_RENDER( Class *cl, Object *o, struct gpRender *gpr )
{
struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
dbug( kprintf( "GM_RENDER\n" ); )
// if( gpr->gpr_Redraw == GREDRAW_REDRAW )
{
struct RastPort *rp = gpr->gpr_RPort;
struct ColorMap *cm = NULL;
struct IBox gbox;
LONG bgpen=id->BackgroundPen, wfpen=id->WaveformPen;
UWORD *pens = gpr->gpr_GInfo->gi_DrInfo->dri_Pens;
WORD x,y, w,h;
gbox = GetAbsGadgetBox( &gpr->gpr_GInfo->gi_Domain, EXTG( o ), FALSE );
x = gbox.Left; y = gbox.Top;
w = gbox.Width; h = gbox.Height;
if( id->ControlPanel )
{
h -= ( id->TapeDeckHeight + 2 );
}
if( ( x != SHRT_MAX && y != SHRT_MAX ) && ( w >=16 && h >= 8 ) )
{
if( gpr->gpr_GInfo->gi_Screen )
{
cm = gpr->gpr_GInfo->gi_Screen->ViewPort.ColorMap;
}
SetAPen( rp, ( bgpen == -1L ) ? pens[TEXTPEN] : bgpen );
RectFill( rp, x,y, w+x-1, h+y-1 );
x += 4; y += 2;
w -= 8; h -= 4;
SetAPen( rp, ( wfpen == -1L ) ? pens[HIGHLIGHTTEXTPEN] : wfpen );
DrawWaveform( cb, rp, id, x, y, w, h );
}
if( id->ControlPanel )
{
/* SetAPen( rp, 4L );
RectFill( rp, gbox.Left, gbox.Top+=(gbox.Height-id->TapeDeckHeight-3),
gbox.Left+gbox.Width-1, gbox.Top+id->TapeDeckHeight+1 );*/
if( gbox.Height >= ( id->TapeDeckHeight + 2 ) )
{
if( gbox.Width >= 201)
{
DoMethodA( (Object *)id->TapeDeckGadget, (Msg) gpr );
if( gbox.Width >= 220 )
{
DoMethodA( (Object *) id->VolumeSlider, (Msg) gpr );
if( ! cb->cb_NoGTSlider )
{
Object *img;
if( img = NewObject( NULL, FRAMEICLASS,
IA_Left, id->VolumeSlider->LeftEdge - 4,
IA_Top, id->VolumeSlider->TopEdge - 2,
IA_Width, id->VolumeSlider->Width + 8,
IA_Height, id->TapeDeckHeight,
IA_FrameType, FRAME_BUTTON,
IA_EdgesOnly, TRUE,
TAG_DONE ) )
{
DrawImageState( rp, (struct Image *)img, 0,0, IDS_NORMAL, gpr->gpr_GInfo->gi_DrInfo );
DisposeObject( img );
}
}
}
}
}
}
if( G( o )->Flags & GFLG_DISABLED )
{
ULONG patt = 0x11114444;
SetAfPt(rp, (UWORD *)&patt, 1);
SetAPen( rp, pens[ SHADOWPEN ] );
RectFill( rp, gbox.Left, gbox.Top, gbox.Left+gbox.Width-1, gbox.Top+gbox.Height-1 );
SetAfPt( rp, NULL, 0L );
}
}/*
else if( gpr->gpr_Redraw == GREDRAW_UPDATE )
{
}*/
return( TRUE );
}
/****************************************************************************/
ULONG __regargs Sound_DRAW( Class *cl, Object *o, struct dtDraw *dtd )
{
struct InstanceData *id = INST_DATA( cl, o );
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
struct RastPort *rp = dtd->dtd_RPort;
struct DrawInfo *dri;
struct Screen *scr;
struct ColorMap *cm = NULL;
UWORD x = dtd->dtd_Left, y = dtd->dtd_Top, *pens,
w = dtd->dtd_Width, h = dtd->dtd_Height;
WORD bgpen = -1, wfpen = -1;
BOOL freedri;
dbug( kprintf( "DTM_DRAW\n" ); )
if( scr = id->Screen )
{
dri = GetScreenDrawInfo( scr );
freedri = TRUE;
}
else
{
dri = id->DrawInfo;
freedri = FALSE;
}
if( dri )
{
pens = dri->dri_Pens;
if( scr )
{
cm = scr->ViewPort.ColorMap;
ObtainSemaphoreShared( &cb->cb_LibLock );
bgpen = ObtainBestPenA( cm,
cb->cb_BgCol[0], cb->cb_BgCol[1], cb->cb_BgCol[2], NULL );
wfpen = ObtainBestPenA( cm,
cb->cb_WfCol[0], cb->cb_WfCol[1], cb->cb_WfCol[2], NULL );
ReleaseSemaphore( &cb->cb_LibLock );
}
SetAPen( rp, ( bgpen == -1L ) ? pens[TEXTPEN] : bgpen );
RectFill( rp, x,y, w+x-1, h+y-1 );
x += 4; y += 2;
w -= 8; h -= 4;
SetAPen( rp, ( wfpen == -1L ) ? pens[HIGHLIGHTTEXTPEN] : wfpen );
DrawWaveform( cb, rp, id, x, y, w, h );
if( cm )
{
ReleasePen( cm, bgpen );
ReleasePen( cm, wfpen );
}
if( freedri )
{
FreeScreenDrawInfo( scr, dri );
}
}
return( dri != NULL );
}
/****************************************************************************/
ULONG __regargs Sound_HITTEST( Class *cl, Object *o, struct gpHitTest *gpht )
{
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
ULONG retval = GMR_GADGETHIT;
WORD h = G(o)->Height;
dbug( kprintf( "GM_HITTEST\n" ); )
if( ! ( G( o )->Flags & GFLG_DISABLED ) )
{
/* calculate absolute high */
if( G(o)->Flags & GFLG_RELHEIGHT )
{
h += gpht->gpht_GInfo->gi_Domain.Height;
}
/* check if one of our members was hit */
if( gpht->gpht_Mouse.Y > ( h - ( id->TapeDeckHeight + 3 ) ) )
{
if( id->ControlPanel )
{
struct IBox domain;
domain = GetAbsGadgetBox( &gpht->gpht_GInfo->gi_Domain, EXTG( o ), FALSE );
if( ! DoMemberHitTest( &domain, (Object *) id->TapeDeckGadget, gpht ) )
{
if( ! DoMemberHitTest( &domain, (Object *) id->VolumeSlider, gpht ) )
{
retval = 0L;
}
}
}
}
else
{
/* We were hit, change return code if it was GM_HELPTEST */
if( gpht->MethodID == GM_HELPTEST )
{
retval = GMR_HELPHIT;
}
}
}
else
{
retval = 0L;
}
return retval;
}
/****************************************************************************/
ULONG __regargs Sound_HANDLEINPUT( Class *cl, Object *o, struct gpInput *gpi )
{
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct InputEvent *ie = gpi->gpi_IEvent;
struct DTSpecialInfo *si = (struct DTSpecialInfo *)G( o )->SpecialInfo;
struct IBox gbox = GetAbsGadgetBox( &gpi->gpi_GInfo->gi_Domain, EXTG( o ), FALSE );
ULONG retval = GMR_MEACTIVE;
WORD mx = gpi->gpi_Mouse.X, my = gpi->gpi_Mouse.Y;
dbug( kprintf("GM_GOACTIVE / GM_HANDLEINPUT\n"); )
/* no input processing during layout */
if( si->si_Flags & DTSIF_LAYOUT )
{
return GMR_NOREUSE;
}
/* check if we're hit or one of our members */
if( gpi->MethodID == GM_GOACTIVE )
{
G( o )->Activation |= GACT_ACTIVEGADGET;
G( o )->Flags |= GFLG_SELECTED;
/* check if mousepointer is over one of our members */
if( id->ControlPanel )
{
if( my > ( gbox.Height - id->TapeDeckHeight - 3 ) )
{
struct gpHitTest gpht = { GM_HITTEST, gpi->gpi_GInfo, mx, my };
if( gbox.Width >= 201 && DoMemberHitTest( &gbox, (Object *) id->TapeDeckGadget, &gpht ) )
{
id->ActiveMember = id->TapeDeckGadget;
}
else if( gbox.Width >= 220 && DoMemberHitTest( &gbox, (Object *) id->VolumeSlider, &gpht ) )
{
id->ActiveMember = id->VolumeSlider;
}
/* nothing hit ? */
if( ! id->ActiveMember )
{
retval = GMR_NOREUSE;
}
}
}
}
/* pass input to the active member ( if there's one ) */
if( id->ActiveMember )
{
struct IBox domain = gbox;
gbox = GetAbsGadgetBox( &gpi->gpi_GInfo->gi_Domain, EXTG( id->ActiveMember ), FALSE );
(gpi -> gpi_Mouse . X) -= ((gbox . Left) - (domain . Left));
(gpi -> gpi_Mouse . Y) -= ((gbox . Top) - (domain . Top));
if( ( retval = DoMethodA( (Object *) id->ActiveMember, (Msg) gpi ) ) & GMR_VERIFY )
{ /* tapedeck.gadget doesn't send OM_UPDATE :( */
if( id->ActiveMember == id->TapeDeckGadget )
{
if( ie->ie_Code == IECODE_LBUTTON )
{
ULONG stm = 0L;
dbug( kprintf( "TapeDeck ICSPECIAL_CODE: %04lx\n", *gpi->gpi_Termination ); )
if( *gpi->gpi_Termination & 0x1000 )
{
stm = STM_PAUSE;
}
else
{
switch( *gpi->gpi_Termination )
{
case BUT_PLAY:
stm = STM_PLAY;
break;
case BUT_STOP:
stm = STM_STOP;
break;
}
}
if( stm )
{
CoerceMethod( cl, o, DTM_TRIGGER, NULL, stm, NULL );
}
}
}
}
(gpi -> gpi_Mouse . X) += ((gbox . Left) - (domain . Left));
(gpi -> gpi_Mouse . Y) += ((gbox . Top) - (domain . Top));
}
/* we're hit */
else if( retval == GMR_MEACTIVE )
{
while( ie )
{
if( ie->ie_Class == IECLASS_RAWMOUSE )
{
/* test for mark mode */
if( si->si_Flags & DTSIF_DRAGSELECT )
{
struct RastPort *rp;
WORD mx = gpi->gpi_Mouse.X, x, y, w, h;
x = gbox.Left; y = gbox.Top + 2;
w = gbox.Width - 8; h = gbox.Height - 4;
if( id->ControlPanel )
{
h -= ( id->TapeDeckHeight + 2 );
}
if( mx > (w+3) )
{
mx = w+3;
}
else if( mx < 4 )
{
mx = 4;
}
if( id->MarkMode )
{
if( id->MaxX != (x+mx) )
{
if( rp = ObtainGIRPort( gpi->gpi_GInfo ) )
{
UWORD minX, maxX;
SetDrMd( rp, COMPLEMENT );
minX = id->MinX;
maxX = id->MaxX;
if( minX > maxX )
{
maxX = minX;
minX = id->MaxX;
}
//WaitTOF();
RectFill( rp, minX, y, maxX, y+h-1 );
minX = id->MinX;
maxX =
id->MaxX = x + mx;
if( minX > maxX )
{
maxX = minX;
minX = id->MaxX;
}
//WaitTOF();
RectFill( rp, minX, y, maxX, y+h-1 );
/* fixes a bug (?) of tapedeck.gadget */
SetDrMd( rp, JAM1 );
ReleaseGIRPort( rp );
}
}
}
/* start mark mode */
else if( ie->ie_Code == IECODE_LBUTTON )
{
if( id->MinX != ~0L )
{
DoMethod( o, DTM_CLEARSELECTED, (ULONG) gpi->gpi_GInfo );
}
id->MarkMode = TRUE;
id->MinX =
id->MaxX = x + mx;
}
}
/* not in mark mode - start or stop playing */
else if( ie->ie_Code == IECODE_LBUTTON )
{
struct timeval tv = gpi->gpi_IEvent->ie_TimeStamp;
STATIC ULONG stm[] = { STM_PLAY, STM_STOP };
CoerceMethod( cl, o, DTM_TRIGGER, NULL, stm[ DoubleClick( id->LastClick.tv_secs, id->LastClick.tv_micro, tv.tv_secs, tv.tv_micro ) ], 0L );
id->LastClick = tv;
}
if( ie->ie_Code == SELECTUP )
{
retval = GMR_NOREUSE;
break;
}
}
ie = ie->ie_NextEvent;
}
}
return( retval );
}
/****************************************************************************/
ULONG __regargs Sound_GOINACTIVE( Class *cl, Object *o, struct gpGoInactive *gpgi )
{
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
DoSuperMethodA( cl, o, (Msg) gpgi );
dbug( kprintf("GOINACTIVE\n"); )
if( id->ActiveMember )
{
DoMethodA( (Object *) id->ActiveMember, (Msg) gpgi );
id->ActiveMember = NULL;
}
id->MarkMode = FALSE;
G( o )->Activation &= ~GACT_ACTIVEGADGET;
G( o )->Flags &= ~GFLG_SELECTED;
return 0L;
}
/****************************************************************************/
ULONG __regargs Sound_TRIGGER( Class *cl, Object *o, struct dtTrigger *dtt )
{
struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
APTR data = NULL;
ULONG cmd = ~0L;
dbug( kprintf("DTM_TRIGGER\n"); )
switch( dtt->dtt_Function )
{
case STM_PLAY:
dbug( kprintf( "STM_PLAY\n" ); )
cmd = COMMAND_PLAY;
data = (APTR) id;
break;
case STM_STOP:
dbug( kprintf( "STM_STOP\n" ); )
cmd = COMMAND_STOP;
break;
case STM_PAUSE:
dbug( kprintf( "STM_PAUSE\n" ); )
cmd = COMMAND_PAUSE;
break;
}
if( cmd != ~0L )
{
SendObjectMsg( id, cmd, data );
}
return 0L;
}
/****************************************************************************/
// "stolen" from embeddt
ULONG __regargs DoMemberHitTest( struct IBox *domain, Object *member, struct gpHitTest *gpht )
{
struct GadgetInfo *gi = gpht -> gpht_GInfo;
struct IBox gbox;
ULONG retval = 0L;
gbox = GetAbsGadgetBox( &gi->gi_Domain, EXTG( member ), (BOOL) ( gpht -> MethodID == GM_HELPTEST ) );
(gpht->gpht_Mouse.X) -= ((gbox.Left) - (domain->Left));
(gpht->gpht_Mouse.Y) -= ((gbox.Top) - (domain->Top));
/* Mouse coordinates must be inside members's select box */
if( ((gpht->gpht_Mouse . X) >= 0) &&
((gpht->gpht_Mouse . Y) >= 0) &&
((gpht->gpht_Mouse . X) <= (gbox.Width)) &&
((gpht->gpht_Mouse . Y) <= (gbox.Height)) )
{
retval = DoMethodA( member, (Msg)gpht );
}
(gpht->gpht_Mouse.X) += ((gbox.Left) - (domain->Left));
(gpht->gpht_Mouse.Y) += ((gbox.Top) - (domain->Top));
return( retval );
}
/****************************************************************************/
struct IBox __regargs GetAbsGadgetBox( struct IBox *domain, struct ExtGadget *g, BOOL useBounds )
{
struct IBox retbox = { 0, 0, 0, 0 };
if( domain && g )
{
if( ((g->MoreFlags) & GMORE_BOUNDS) && useBounds )
{
retbox = *((struct IBox *)(&(g->BoundsLeftEdge)));
}
else
{
retbox = *(GADGET_BOX( g ));
}
if( (g->Flags) & GFLG_RELBOTTOM )
{
(retbox.Top) += ((domain->Top) + (domain->Height));
}
if( (g->Flags) & GFLG_RELRIGHT )
{
(retbox.Left) += ((domain->Left) + (domain->Width));
}
if( (g->Flags) & GFLG_RELWIDTH )
{
(retbox.Width) += (domain->Width);
}
if( (g->Flags) & GFLG_RELHEIGHT )
{
(retbox.Height) += (domain->Height);
}
}
return( retbox );
}
/****************************************************************************/
void __regargs makeqtab( BYTE *qtab )
{
LONG i;
for( i=0; i < 512; i++ )
{
qtab[i] = 0;
}
for ( i = 1; i < 16; i++ )
{
LONG j = 256 + fibtab[i],
k = 256 + fibtab[i-1];
if( fibtab[i] < 0 )
{
while( j > k )
{
qtab[j--] = i;
}
}
else
{
while( j < 512 )
{
qtab[j++] = i;
}
}
}
}
/****************************************************************************/
LONG __regargs WriteChunk( struct ClassBase *cb, struct IFFHandle *iff, ULONG type, ULONG id, APTR data, ULONG size )
{
LONG err;
if( ! ( err = PushChunk( iff, type, id, size ) ) )
{
if( ( err = WriteChunkBytes( iff, data, size ) ) == size )
{
err = PopChunk( iff );
}
}
return err;
}
/****************************************************************************/
LONG __regargs WriteAIFF( struct ClassBase *cb, Object *o, struct IFFHandle *iff, struct InstanceData *id )
{
LONG err;
if( ! ( err = PushChunk( iff, ID_AIFF, ID_FORM, IFFSIZE_UNKNOWN ) ) )
{
CommonChunk common;
UBYTE sampleType = id->SampleType;
ULONG sampleLength = id->SampleLength;
BYTE *sample = id->Sample;
if( id->StartSample != ~0L )
{
sample = &sample[ UMult32( id->StartSample, bytesPerPoint[ sampleType ] ) ];
sampleLength = id->EndSample - id->StartSample;
}
common.numChannels = ( sampleType & 1 ) + 1;
common.numSampleFrames = sampleLength;
common.sampleSize = ( sampleType >= SDTST_M16S ) ? 16 : 8;
ulong2extended( id->Frequency, &common.sampleRate );
if( ! ( err = WriteChunk( cb, iff, ID_AIFF, ID_COMM, &common, sizeof( common ) ) ) )
{
SampledSoundHeader ssnd = { 0L, 0L };
if( ! ( err = PushChunk( iff, ID_AIFF, ID_SSND, IFFSIZE_UNKNOWN ) ) )
{
if( ( err = WriteChunkBytes( iff, &ssnd, sizeof( ssnd ) ) ) == sizeof( ssnd ) )
{
ULONG bytes = UMult32( sampleLength, bytesPerPoint[ sampleType ] );
if( ( err = WriteChunkBytes( iff, sample, bytes ) ) == bytes )
{
err = PopChunk( iff );
}
}
}
}
if( ! err )
{
err = PopChunk( iff );
}
}
return( err );
}
/****************************************************************************/
LONG __regargs WriteSVX( struct ClassBase *cb, Object *o, struct IFFHandle *iff, struct InstanceData *id )
{
UBYTE sampletype = id->SampleType, bps = ( sampletype >= SDTST_M16S ? 2 : 1 );
BOOL stereo = IsStereo( id->SampleType );
LONG err, type = ( sampletype >= SDTST_M16S ? ID_16SV : ID_8SVX );
ULONG sampleLength = id->SampleLength;
BYTE *sample = id->Sample;
struct VoiceHeader vhdr;
CopyMem( &id->VoiceHeader, &vhdr, sizeof( vhdr ) );
vhdr.vh_Compression = ( ( id->VoiceHeader.vh_Compression == CMP_FIBDELTA ) || ( cb->cb_Compress ) ) && ( sampletype <= SDTST_S8S );
if( id->StartSample != ~0L )
{
sample = &sample[ UMult( id->StartSample, bytesPerPoint[ sampletype ] ) ];
sampleLength = id->EndSample - id->StartSample;
vhdr.vh_OneShotHiSamples = sampleLength;
vhdr.vh_RepeatHiSamples = 0L;
}
if( ! ( err = PushChunk( iff, type, ID_FORM, IFFSIZE_UNKNOWN ) ) )
{
if( ! ( err = WriteChunk( cb, iff, type, ID_VHDR, &vhdr, sizeof( vhdr ) ) ) )
{
struct ObjectData
{
ULONG attr;
ULONG id;
STRPTR data;
} ObjData[] = {
DTA_ObjName, ID_NAME, NULL,
DTA_ObjAnnotation, ID_ANNO, NULL,
DTA_ObjAuthor, ID_AUTH, NULL,
DTA_ObjCopyright, ID_Copyright, NULL,
DTA_ObjVersion, ID_FVER, NULL,
NULL
};
LONG i;
for( i = 0; ObjData[i].attr; i++ )
{
struct ObjectData *od = &ObjData[i];
if( GetDTAttrs( o, od->attr, (ULONG) &od->data, TAG_DONE ) && od->data )
{
if( ( err = WriteChunk( cb, iff, type, od->id, od->data, strlen( od->data ) ) ) )
{
break;
}
}
}
if( ! err )
{
if( stereo )
{
ULONG chan = 6L;
err = WriteChunk( cb, iff, type, ID_CHAN, &chan, sizeof( ULONG ) );
}
else
{
ULONG pan = 0x10000 - id->Panning;
err = WriteChunk( cb, iff, type, ID_PAN, &pan, sizeof( ULONG ) );
}
}
if( ! err )
{
if( vhdr.vh_Compression == CMP_FIBDELTA )
{
BYTE *qtab, *buf;
LONG buffersize;
buffersize = sampleLength;
while( ! ( buf = AllocVec( buffersize + 512L, MEMF_PUBLIC ) ) )
{
if( ( buffersize /= 2 ) < 1024L )
{
break;
}
}
if( buf )
{
if( ! ( err = PushChunk( iff, type, ID_BODY, IFFSIZE_UNKNOWN ) ) )
{
LONG i;
qtab = &buf[buffersize];
makeqtab( qtab );
for( i = 0; i < (stereo?2:1) && !err; i++ )
{
LONG length = sampleLength, samples = 0L;
BYTE c0 = 0, *src = &sample[i], add = stereo?2:1;
UBYTE o, x = 1;
if( length & 1 )
{
c0 = *src++;
length--;
}
buf[ 0 ] = 0;
buf[ 1 ] = c0;
samples += 2;
while( length-- )
{
UBYTE n;
c0 += fibtab[ n = qtab[256+(*src-c0)] ];
src+=add;
if( x^=1 )
{
buf[samples++] = o | n;
}
else
{
o = n << 4;
}
if( samples == buffersize || length == 0L )
{
if( ( err = WriteChunkBytes( iff, buf, samples ) ) != samples )
{
break;
}
err = samples = 0L;
}
}
}
if( ! err )
{
err = PopChunk( iff );
}
}
FreeVec( buf );
}
else
{
err = ERROR_NO_FREE_STORE;
}
}
/*
** write uncompressed svx file
*/
else
{
/*
** create a stereo BODY
*/
if( stereo )
{
if( ! ( err = PushChunk( iff, type, ID_BODY, IFFSIZE_UNKNOWN ) ) )
{
BYTE *buf;
LONG bufsize = sampleLength;
while( ! ( buf = AllocVec( UMult( bufsize, bps ), MEMF_PUBLIC ) ) )
{
if( ( bufsize /= 2 ) < 1024L )
{
break;
}
}
if( buf )
{
LONG i;
for( i = 0; i < 2 && ! err; i++, sample+=bps )
{
LONG samples = bufsize, length = sampleLength;
BYTE *src = sample;
while( length )
{
ULONG bytes = UMult( samples, bps );
if( sampletype == SDTST_S16S )
{
WORD *dst = (WORD *)buf,
*src_p = (WORD *)src;
LONG c;
for( c = samples; c; c--, src_p+=2 )
{
*dst++ = *src_p;
}
src = (BYTE *) src_p;
}
else
{
BYTE *dst = buf;
LONG c;
for( c = samples; c; c--, src+=2 )
{
*dst++ = *src;
}
}
if( ( err = WriteChunkBytes( iff, buf, bytes ) ) != bytes )
{
break;
}
if( (length-=samples) < samples )
{
samples = length;
}
err = 0L;
}
}
}
else
{
err = ERROR_NO_FREE_STORE;
}
if( ! err )
{
err = PopChunk( iff );
}
}
}
/*
** write uncompressed mono sample
*/
else
{
err = WriteChunk( cb, iff, type, ID_BODY, sample, UMult( sampleLength, bps ) );
}
}
}
}
if( ! err )
{
err = PopChunk( iff );
}
}
return( err );
}
/****************************************************************************/
ULONG __regargs Sound_WRITE( Class *cl, Object *o, struct dtWrite *dtw )
{
struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
struct InstanceData *id = (struct InstanceData *) INST_DATA( cl, o );
struct IFFHandle *iff;
struct SignalSemaphore *lock = &((struct DTSpecialInfo *)G( o )->SpecialInfo)->si_Lock;
LONG err = 0L;
dbug( kprintf( "DTM_WRITE / DTM_COPY\n" ); )
ObtainSemaphoreShared( &cb->cb_LibLock );
if( id->Sample )
{
ObtainSemaphoreShared( lock );
if( iff = AllocIFF() )
{
if( dtw->MethodID == DTM_WRITE )
{
dbug( kprintf( "DTWM_RAW\n" ); )
if( iff->iff_Stream = dtw->dtw_FileHandle )
{
InitIFFasDOS( iff );
}
else
{
dbug( kprintf( "NULL filehandle\n"); )
err = ERROR_INVALID_LOCK;
}
}
else
{
dbug( kprintf( "DTM_COPY\n" ); )
if( iff->iff_Stream = (ULONG) OpenClipboard( PRIMARY_CLIP ) )
{
InitIFFasClip( iff );
}
else
{
dbug( kprintf( "Cant open clipboard\n" ); )
err = ERROR_OBJECT_IN_USE;
}
}
if( ! err )
{
if( err = OpenIFF( iff, IFFF_WRITE ) )
{
err = ifferr2doserr[-err-1];
dbug( kprintf( "OpenIFF() failed\n" ); )
}
}
}
else
{
err = ERROR_NO_FREE_STORE;
dbug( kprintf( "AllocIFF failed\n" ); )
}
if( ! err )
{
dbug( kprintf( "Everything fine so far ...\n" ); )
if( id->SampleType >= SDTST_M16S && cb->cb_AIFF )
{
err = WriteAIFF( cb, o, iff, id );
}
else
{
err = WriteSVX( cb, o, iff, id );
}
if( err < 0L )
{
err = ifferr2doserr[-err-1];
}
}
else
{
dbug( kprintf( "Something failed\n" ); )
}
dbug( kprintf( "closing iff stream\n" ); )
CloseIFF( iff );
if( dtw->MethodID == DTM_COPY )
{
CloseClipboard( (struct ClipboardHandle *)iff->iff_Stream );
}
FreeIFF( iff );
ReleaseSemaphore( lock );
}
else
{
err = ERROR_REQUIRED_ARG_MISSING;
}
ReleaseSemaphore( &cb->cb_LibLock );
SetIoErr( err );
return( err ? FALSE : TRUE );
}
/****************************************************************************/
/*
** test if dblscan screenmode
** taken from the ahi paula driver by Martin Blom
*/
#if 0
BOOL Is31Khz( struct ClassBase *cb )
{
BOOL ret = FALSE;
/* check for ocs */
#ifdef __MAXON__
extern struct Library *GfxBase, *IntuitionBase;
if( ((struct GfxBase *)GfxBase)->ChipRevBits0 & ( GFXF_HR_DENISE|GFXF_AA_LISA ) )
#else
#undef GfxBase
if( ((struct GfxBase *)cb->cb_GfxBase)->ChipRevBits0 & ( GFXF_HR_DENISE|GFXF_AA_LISA ) )
#define GfxBase cb->cb_GfxBase
#endif
{
ULONG lock, modeid;
lock = LockIBase( 0L );
#ifdef __MAXON__
modeid = GetVPModeID( & ((struct IntuitionBase *)IntuitionBase)->FirstScreen->ViewPort );
#else
#undef IntuitionBase
modeid = GetVPModeID( & ((struct IntuitionBase *)cb->cb_IntuitionBase)->FirstScreen->ViewPort );
#define IntuitionBase cb->cb_IntuitionBase
#endif
UnlockIBase( lock );
/* gfxboard */
if( modeid & 0x40000000 )
{
Forbid();
if( FindTask( "Picasso96" ) )
{
UBYTE buf[16];
Permit();
if( GetVar( "Picasso96/AmigaVideo", buf, sizeof( buf ), GVF_GLOBAL_ONLY ) )
{
if( ! Strnicmp( buf, "31Khz" , 5L ) )
{
ret = TRUE;
}
}
}
else
{
#ifdef __MAXON__
struct copinit *ci = ((struct GfxBase *)GfxBase)->copinit;
#else
#undef GfxBase
struct copinit *ci = ((struct GfxBase *)cb->cb_GfxBase)->copinit;
#define GfxBase cb->cb_GfxBase
#endif
Permit();
if( ( ci->fm0[ 0 ] != 0x01fc ) || ( ci->fm0[ 1 ] & 0xc000 ) )
{
ret = TRUE;
}
}
}
/* native screen */
else
{
struct MonitorInfo moni;
if( GetDisplayInfoData( NULL, (UBYTE *) &moni, sizeof( moni ), DTAG_MNTR, modeid ) )
{
if( moni.TotalColorClocks * moni.TotalRows / ( 2 * ( moni.TotalRows - moni.MinRow + 1 ) ) <= 64 )
{
ret = TRUE;
}
}
}
}
return ret;
}
#endif
/****************************************************************************/
void __regargs CalcPanVol( UWORD overall, ULONG pan, UWORD *leftvol, UWORD *rightvol )
{
pan = ( pan << 6 ) >> 16;
*rightvol = pan ? overall / ( 64 / pan ) : 0;
*leftvol = overall - *rightvol;
}
/****************************************************************************/
void __regargs RemoveRequest( struct IORequest *ior )
{
#ifndef __MAXON__
#undef SysBase
struct Library *SysBase = (*(struct Library **)4L);
#endif
struct Node *ln, *succ;
Disable();
for( ln = ior->io_Message.mn_ReplyPort->mp_MsgList.lh_Head;
succ = ln->ln_Succ; ln = succ )
{
if( ln == &ior->io_Message.mn_Node )
{
Remove( ln );
SetSignal( 0L, 1L << ior->io_Message.mn_ReplyPort->mp_SigBit );
break;
}
}
Enable();
#ifndef __MAXON__
#undef SysBase
#define SysBase cb->cb_SysBase
#endif
}
/****************************************************************************/
#define LEFT_CHANNEL_0 1
#define RIGHT_CHANNEL_1 2
#define RIGHT_CHANNEL_2 4
#define LEFT_CHANNEL_3 8
#define MAX_SAMPLE 131072
#define MAX_SAMPLE_RATE 28867
#define LEFT_MASK (LEFT_CHANNEL_0|LEFT_CHANNEL_3)
#define RIGHT_MASK (RIGHT_CHANNEL_1|RIGHT_CHANNEL_2)
enum {
AUDIO_CONTROL,
AUDIO_LEFT,
AUDIO_LEFT2,
AUDIO_RIGHT,
AUDIO_RIGHT2,
NUM_REQUESTS
};
/****************************************************************************/
void __regargs SetTDMode( struct ClassBase *cb, struct InstanceData *id, ULONG mode )
{
if( id->ControlPanel )
{
ULONG oldmode = mode;
ObtainSemaphoreShared( &id->Lock );
/* avoid deadlocks */
GetAttr( TDECK_Mode, id->TapeDeckGadget, &oldmode );
if( oldmode != mode )
{
SetGadgetAttrs( id->TapeDeckGadget, id->Window, id->Requester,
TDECK_Mode, mode, TAG_DONE );
}
ReleaseSemaphore( &id->Lock );
}
}
/****************************************************************************/
void PlayerProc( void )
{
#ifndef __MAXON__
#undef SysBase
struct Library *SysBase = *(struct Library **)4L;
#endif
struct Process *pr = (struct Process *) FindTask( NULL );
struct MsgPort *mp, *mpaudio = NULL;
struct IOAudio *ioaudio[NUM_REQUESTS] = { };
struct ClassBase *cb;
struct InstanceData *id;
LONG numChAllocated, samples, buffersize, length, cycles,
loops, audiompmsk, mpmsk;
BOOL releaseAudio = FALSE, restart, paused = FALSE;
BYTE *sample, *buffer[4] = {};
mp = &pr->pr_MsgPort;
mpmsk = 1L << mp->mp_SigBit;
dbug( kprintf("child process launched\n"); )
for( ;; )
{
struct ObjectMsg *msg;
LONG rcv;
rcv = Wait( mpmsk | audiompmsk );
if( rcv & mpmsk )
{
while( msg = (struct ObjectMsg *) GetMsg( mp ) )
{
switch( msg->Command )
{
case COMMAND_NEXT_BUFFER:
if( releaseAudio )
{
ObtainSemaphoreShared( &id->Lock );
sample = id->Sample;
length = id->SampleLength;
samples = ( length > buffersize ) ? buffersize : length;
rcv = audiompmsk;
ReleaseSemaphore( &id->Lock );
}
break;
case COMMAND_INIT:
dbug( kprintf( "child/COMMAND_INIT\n"); )
id = (struct InstanceData *) msg->Data;
cb = id->ClassBase;
if( ! ( msg->Data = mp = CreateMsgPort() ) )
{
ReplyMsg( &msg->Message );
return;
}
mpmsk = 1L << mp->mp_SigBit;
break;
case COMMAND_EXIT:
case COMMAND_STOP:
dbug( kprintf( "child/COMMAND_EXIT or STOP\n"); )
if( releaseAudio )
{
LONG i;
SetTDMode( cb, id, BUT_STOP );
for( i = AUDIO_LEFT; i < NUM_REQUESTS; i++ )
{
struct IORequest *ioa = (struct IORequest *) ioaudio[ i ];
if( CheckIO( ioa ) )
{
RemoveRequest( ioa );
}
else
{
AbortIO( ioa );
WaitIO( ioa );
}
}
CloseDevice( (struct IORequest *) ioaudio[ AUDIO_CONTROL ] );
DeleteMsgPort( mpaudio );
audiompmsk = 0L;
FreeVec( ioaudio[ AUDIO_CONTROL ] );
FreeVec( buffer[0] ); buffer[0] = NULL;
releaseAudio = FALSE;
}
if( msg->Command == COMMAND_EXIT )
{
Forbid();
ReplyMsg( &msg->Message );
DeleteMsgPort( mp );
return;
}
break;
case COMMAND_PERVOL:
{
dbug( kprintf( "child/COMMAND_PERVOL\n"); )
if( releaseAudio )
{
struct IOAudio *ioa = ioaudio[ AUDIO_CONTROL ];
ObtainSemaphoreShared( &id->Lock );
if( numChAllocated == 1L || IsStereo( id->SampleType ) )
{
ioa->ioa_Period = Freq2Period( id->Frequency );
ioa->ioa_Volume = id->Volume;
ioa->ioa_Request.io_Flags = 0;
ioa->ioa_Request.io_Command = ADCMD_PERVOL;
DoIO( &ioa->ioa_Request );
Forbid();
ioaudio[ AUDIO_LEFT ]->ioa_Volume =
ioaudio[ AUDIO_LEFT2 ]->ioa_Volume =
ioaudio[ AUDIO_RIGHT ]->ioa_Volume =
ioaudio[ AUDIO_RIGHT2 ]->ioa_Volume = id->Volume;
Permit();
}
else
{
UWORD leftvol, rightvol;
ULONG oldmask = (ULONG) ioa->ioa_Request.io_Unit;
CalcPanVol( id->Volume, id->Panning, &leftvol, &rightvol );
/*
ioa->ioa_Request.io_Command = CMD_STOP;
DoIO( &ioa->ioa_Request );*/
ioa->ioa_Request.io_Unit = (struct Unit *) ( oldmask & LEFT_MASK );
ioa->ioa_Period = Freq2Period( id->Frequency );
ioa->ioa_Volume = leftvol;
ioa->ioa_Request.io_Flags = 0;
ioa->ioa_Request.io_Command = ADCMD_PERVOL;
DoIO( &ioa->ioa_Request );
ioa->ioa_Request.io_Unit = (struct Unit *) ( oldmask & RIGHT_MASK );
ioa->ioa_Period = Freq2Period( id->Frequency );
ioa->ioa_Volume = rightvol;
ioa->ioa_Request.io_Flags = 0;
ioa->ioa_Request.io_Command = ADCMD_PERVOL;
DoIO( &ioa->ioa_Request );
ioa->ioa_Request.io_Unit = (struct Unit *) oldmask;
Forbid();
ioaudio[ AUDIO_LEFT ]->ioa_Volume =
ioaudio[ AUDIO_LEFT2 ]->ioa_Volume = leftvol;
ioaudio[ AUDIO_RIGHT ]->ioa_Volume =
ioaudio[ AUDIO_RIGHT2 ]->ioa_Volume = rightvol;
Permit();
/*
ioa->ioa_Request.io_Command = CMD_START;
DoIO( &ioa->ioa_Request );*/
}
Forbid();
ioaudio[ AUDIO_LEFT ]->ioa_Period =
ioaudio[ AUDIO_LEFT2 ]->ioa_Period =
ioaudio[ AUDIO_RIGHT ]->ioa_Period =
ioaudio[ AUDIO_RIGHT2 ]->ioa_Period = Freq2Period( id->Frequency );
Permit();
ReleaseSemaphore( &id->Lock );
}
}
break;
case COMMAND_PAUSE:
{
dbug( kprintf( "child/COMMAND_PAUSE\n"); )
if( releaseAudio )
{
if( ! paused )
{
ioaudio[ AUDIO_CONTROL ]->ioa_Request.io_Command = CMD_STOP;
DoIO( &ioaudio[ AUDIO_CONTROL ]->ioa_Request );
paused = TRUE;
}
}
}
break;
case COMMAND_PLAY:
{
dbug( kprintf( "child/COMMAND_PLAY\n"); )
ObtainSemaphoreShared( &id->Lock );
if( releaseAudio )
{
if( paused )
{
rcv = audiompmsk;
restart = TRUE;
paused = FALSE;
}
else
{
LONG i;
for( i = AUDIO_LEFT; i < NUM_REQUESTS; i++ )
{
struct IORequest *ioa = &ioaudio[ i ]->ioa_Request;
if( CheckIO( ioa ) )
{
RemoveRequest( ioa );
}
else
{
AbortIO( ioa );
WaitIO( ioa );
}
}
sample = id->Sample;
length = id->SampleLength;
samples = buffersize;
if( length <= buffersize )
{
loops = 1L;
cycles = id->Cycles;
}
else
{
loops = id->Cycles;
cycles = 1L;
}
}
}
else
{
UBYTE ChMap[] = {
LEFT_CHANNEL_0 | RIGHT_CHANNEL_1,
LEFT_CHANNEL_3 | RIGHT_CHANNEL_2,
LEFT_CHANNEL_0, LEFT_CHANNEL_3,
RIGHT_CHANNEL_1, RIGHT_CHANNEL_2
};
struct IOAudio *ioa;
LONG i;
if( ! id->Sample || ! id->SampleLength )
{
break;
}
dbug( kprintf( "child/allocating requests\n" ); )
/*- allocate requests and msgport -*/
if( ! ( ioa = AllocVec( sizeof( *ioa ) * NUM_REQUESTS, MEMF_PUBLIC|MEMF_CLEAR ) ) ||
! ( mpaudio = CreateMsgPort() ) )
{
FreeVec( ioa );
SetTDMode( cb, id, BUT_STOP );
break;
}
for( i = 0; i < NUM_REQUESTS; i++ )
{
ioaudio[i] = ioa++;
}
audiompmsk = 1L << mpaudio->mp_SigBit;
/*- Open audio.device and intialize requests -*/
ioa = ioaudio[ AUDIO_CONTROL ];
ioa->ioa_Request.io_Message.mn_ReplyPort = mpaudio;
ioa->ioa_Request.io_Message.mn_Length = sizeof( *ioa );
ioa->ioa_Data = ChMap;
ioa->ioa_Length = sizeof( ChMap );
if( ! OpenDevice( "audio.device", 0L, (struct IORequest *) ioa, 0L ) )
{
/*- make CheckIO() work -*/
ioa->ioa_Request.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
for( i = 1; i < NUM_REQUESTS; i++ )
{
CopyMem( ioa, ioaudio[i], sizeof( *ioa ) );
}
for( i = 0; i < sizeof( ChMap ); i++ )
{
if( (ULONG) ioa->ioa_Request.io_Unit == (ULONG) ChMap[i] )
{
break;
}
}
if( i < 2 )
{
dbug( kprintf( "child/got two stereo channels\n" ); )
numChAllocated = 2L;
/*- stop device in order to sync stereo channels -*/
ioa->ioa_Request.io_Command = CMD_STOP;
DoIO( &ioa->ioa_Request );
restart = TRUE;
}
else
{
dbug( kprintf( "child/got only one channel\n" ); )
numChAllocated = 1L;
restart = FALSE;
}
ioaudio[ AUDIO_LEFT ]->ioa_Request.io_Unit =
ioaudio[ AUDIO_LEFT2 ]->ioa_Request.io_Unit = (struct Unit *) ( (ULONG) ioa->ioa_Request.io_Unit & LEFT_MASK );
ioaudio[ AUDIO_RIGHT ]->ioa_Request.io_Unit =
ioaudio[ AUDIO_RIGHT2 ]->ioa_Request.io_Unit = (struct Unit *) ( (ULONG) ioa->ioa_Request.io_Unit & RIGHT_MASK );
sample = id->Sample;
length = id->SampleLength;
if( ( id->SampleType == SDTST_M8S ) && ( TypeOfMem( sample ) & MEMF_CHIP ) )
{
buffersize = samples = ( length > MAX_SAMPLE ) ? MAX_SAMPLE : length;
dbug( kprintf( "child/chip sample\n" ); )
}
/*- allocate buffers -*/
else
{
ObtainSemaphoreShared( &cb->cb_LibLock ); /* determine buffersize, don't go below 1k (heavy system load) */
buffersize = ( length > cb->cb_BufferSize ) ? cb->cb_BufferSize : ( ((length+1)/2) < 1024L ? length : (length+1)/2 );
ReleaseSemaphore( &cb->cb_LibLock );
while( ! ( buffer[0] = AllocVec( buffersize << numChAllocated, MEMF_CHIP ) ) )
{
dbug( kprintf( "child/failed to allocate %ld bytes of buffer\n", buffersize ); )
if( (buffersize /= 2) < 1024L )
{
break;
}
}
samples = buffersize;
dbug( kprintf( "child/Buffer at %08lx, size %ld, num %ld\n", buffer[0], buffersize, numChAllocated*2 ); )
if( buffer[0] == NULL )
{
CloseDevice( (struct IORequest *) ioa );
DeleteMsgPort( mpaudio );
audiompmsk = 0L;
FreeVec( ioa );
SetTDMode( cb, id, BUT_STOP );
break;
}
for( i = 1; i < 4; i++ )
{
buffer[ i ] = buffer[ i-1 ] + buffersize;
}
}
if( buffersize <= length )
{
cycles = id->Cycles;
loops = 1L;
}
else
{
cycles = 1L;
loops = id->Cycles;
}
dbug( kprintf( "child/Sample: %08lx, Length: %ld, Cycles: %ld, Loops: %ld, Freq: %ld\n", sample, length, cycles, loops, id->Frequency ); )
releaseAudio = TRUE;
rcv = audiompmsk;
SetTDMode( cb, id, BUT_PLAY );
}
else
{
dbug( kprintf("child/can't open audio.device\n"); )
DeleteMsgPort( mpaudio );
audiompmsk = 0L;
FreeVec( ioa );
SetTDMode( cb, id, BUT_STOP );
}
}
ReleaseSemaphore( &id->Lock );
}
break;
} // switch
if( msg->Message.mn_ReplyPort )
{
ReplyMsg( &msg->Message );
}
else // NT_FREEMSG
{
FreeVec( msg );
}
} // while
} // if
if( rcv & audiompmsk )
{
ObtainSemaphoreShared( &id->Lock );
if( length == 0L )
{
LONG i;
BOOL Done = TRUE;
dbug( kprintf( "child/reachend end of sample\n" ); )
/*- wait for any outstanding request -*/
for( i = AUDIO_LEFT; i < NUM_REQUESTS; i++ )
{
struct IORequest *ioa = &ioaudio[i]->ioa_Request;
if( ! CheckIO( ioa ) )
{
/* don't block doing WaitIO() */
Done = FALSE;
}
else
{
RemoveRequest( ioa );
}
}
if( ! Done || id->Continuous )
{
ReleaseSemaphore( &id->Lock );
continue;
}
if( id->Repeat || ( --loops > 0L ) )
{
dbug( kprintf( "child/%ld loops to go\n", loops ); )
sample = id->Sample;
length = id->SampleLength;
samples = buffersize;
/*- stop device in order to sync stereo channels -*/
if( numChAllocated == 2L )
{
ioaudio[ AUDIO_CONTROL ]->ioa_Request.io_Command = CMD_STOP;
DoIO( &ioaudio[ AUDIO_CONTROL ]->ioa_Request );
restart = TRUE;
}
else
{
restart = FALSE;
}
}
else
{
dbug( kprintf("child/cleanup\n"); )
/*- cleanup -*/
CloseDevice( &ioaudio[AUDIO_CONTROL]->ioa_Request );
FreeVec( buffer[0] ); buffer[0] = NULL;
FreeVec( ioaudio[ AUDIO_CONTROL ] );
DeleteMsgPort( mpaudio ); audiompmsk = 0L;
releaseAudio = FALSE;
SetTDMode( cb, id, BUT_STOP );
if( id->SignalTask && id->SignalBit != -1L )
{
Signal( id->SignalTask, 1L << id->SignalBit );
}
}
}
if( length )
{
LONG i;
UWORD volleft, volright;
if( numChAllocated == 1L || IsStereo( id->SampleType ) )
{
volright =
volleft = id->Volume;
}
else
{
CalcPanVol( id->Volume, id->Panning, &volleft, &volright );
}
/*- we work doublebuffered -*/
for( i = 0; i < 2; i++ )
{
struct IOAudio *ioa_left = ioaudio[ i + AUDIO_LEFT ],
*ioa_right = ioaudio[ i + AUDIO_RIGHT ];
/*- get free audiorequest -*/
if( CheckIO( (struct IORequest *) ioa_left ) && CheckIO( (struct IORequest *) ioa_right ) )
{
BYTE *data_left, *data_right;
dbug( kprintf( "child/Request pair #%ld is free\n", i ); )
RemoveRequest( (struct IORequest *) ioa_left );
RemoveRequest( (struct IORequest *) ioa_right );
if( buffer[ 0 ] )
{
if( IsStereo( id->SampleType ) )
{
LONG c, add = ( id->SampleType == SDTST_S16S ) ? 2 : 1;
if( numChAllocated == 2L )
{
BYTE *buf_left = buffer[ i * 2 ],
*buf_right = buffer[ i * 2 + 1 ];
data_left = buf_left;
data_right = buf_right;
for( c = samples; c; c-- )
{
*buf_left++ = *sample; sample += add;
*buf_right++ = *sample; sample += add;
}
}
else
{
BYTE *buf = buffer[ i ];
data_left =
data_right = buf;
for( c = samples; c; c--, sample+=(add<<1) )
{
*buf++ = ( sample[0] + sample[add] ) >> 1;
}
}
}
else
{
BYTE *buf = buffer[ i ];
data_left =
data_right = buf;
if( id->SampleType == SDTST_M8S )
{
if( (ULONG) sample&3 || (ULONG) buf&3 || samples&3 )
{
CopyMem( sample, buf, samples );
}
else
{
CopyMemQuick( sample, buf, samples );
}
sample += samples;
}
else
{
LONG c;
for( c = samples; c; c--, sample+=2 )
{
*buf++ = *sample;
}
}
}
}
else
{
data_left =
data_right = sample;
sample += samples;
}
ioa_left->ioa_Data = data_left;
ioa_left->ioa_Length = samples;
ioa_left->ioa_Cycles = cycles;
ioa_left->ioa_Period = Freq2Period( id->Frequency );
ioa_left->ioa_Volume = volleft;
ioa_left->ioa_Request.io_Flags = ADIOF_PERVOL;
ioa_left->ioa_Request.io_Command = CMD_WRITE;
BeginIO( (struct IORequest *) ioa_left );
if( numChAllocated == 2L )
{
ioa_right->ioa_Data = data_right;
ioa_right->ioa_Length = samples;
ioa_right->ioa_Cycles = cycles;
ioa_right->ioa_Period = Freq2Period( id->Frequency );
ioa_right->ioa_Volume = volright;
ioa_right->ioa_Request.io_Flags = ADIOF_PERVOL;
ioa_right->ioa_Request.io_Command = CMD_WRITE;
BeginIO( (struct IORequest *) ioa_right );
}
if( (length-=samples) < samples )
{
samples = length;
} // if
} // if
else
{
dbug( kprintf( "child/Req #%ld in use\n", i ); )
}
if( ! length )
{
/* a continuous stream of data? */
if( id->Continuous )
{
/* notify */
if( id->SignalTask && id->SignalBit != -1L )
{
Signal( id->SignalTask, 1L << id->SignalBit );
}
}
break;
}
} // for
if( restart )
{
dbug( kprintf( "child/starting stereo channels\n" ); )
ioaudio[ AUDIO_CONTROL ]->ioa_Request.io_Command = CMD_START;
DoIO( &ioaudio[ AUDIO_CONTROL ]->ioa_Request );
restart = FALSE;
} // if
} // if
ReleaseSemaphore( &id->Lock );
} // if
} // while
#ifndef __MAXON__
#define SysBase cb->cb_SysBase
#endif
}
/****************************************************************************/
void __regargs CloseAHI( struct MsgPort *mp, struct AHIRequest *ahir )
{
#ifndef __MAXON__
#undef SysBase
struct Library *SysBase = (*(struct Library **)4L);
#endif
CloseDevice( (struct IORequest *) ahir );
DeleteIORequest( (struct IORequest *) ahir );
DeleteMsgPort( mp );
#ifndef __MAXON__
#define SysBase cb->cb_SysBase
#endif
}
/****************************************************************************/
struct Library * __regargs OpenAHI( struct MsgPort **mpp, struct AHIRequest **iop )
{
#ifndef __MAXON__
#undef SysBase
struct Library *SysBase = (*(struct Library **)4L);
#endif
struct MsgPort *mp;
struct AHIRequest *ahir;
mp = CreateMsgPort();
if( ahir = (struct AHIRequest *) CreateIORequest( mp, sizeof( struct AHIRequest ) ) )
{
ahir->ahir_Version = 4;
if( ! OpenDevice( "ahi.device", AHI_NO_UNIT, (struct IORequest *)ahir, 0L ) )
{
*mpp = mp;
*iop = ahir;
return( (struct Library *) ahir->ahir_Std.io_Device );
}
else
{
dbug( kprintf( "Can't open ahi.device v4\n" ); )
}
DeleteIORequest( (struct IORequest *) ahir );
}
else
{
dbug( kprintf( "no memory for ahirequest or msgport\n" ); )
}
DeleteMsgPort( mp );
return FALSE;
#ifndef __MAXON__
#define SysBase cb->cb_SysBase
#endif
}
/****************************************************************************/
struct SoundFuncData {
UWORD CyclesLeft;
UWORD Cycles;
UWORD Channels;
UWORD Sound;
BOOL Continuous;
BOOL Valid[2];
BOOL Restart;
BOOL *Repeat;
struct Task *SigTask;
#ifndef __MAXON__
#undef SysBase
struct Library *AHIBase;
struct Library *SysBase;
#define AHIBase sfd->AHIBase
#define SysBase sfd->SysBase
#endif
};
#ifdef __MAXON__
void SoundFunc( struct Hook *h, struct AHIAudioCtrl *actrl, struct AHISoundMessage *ahism )
#else
void __interrupt SoundFunc( REG(a0, struct Hook *h), REG(a2, struct AHIAudioCtrl *actrl), REG(a1, struct AHISoundMessage *ahism) )
#endif
{
struct SoundFuncData *sfd = (struct SoundFuncData *) h->h_Data;
dbug( kprintf( "SoundFunc\n" ); )
if( ! ( *sfd->Repeat ) )
{
if( ! ( sfd->CyclesLeft-- ) )
{
LONG i, snd = sfd->Sound;
sfd->Valid[ snd ] = FALSE;
sfd->Sound = snd = ( sfd->Continuous ) ? ! snd : AHI_NOSOUND;
/* no echos please */
if( ! sfd->Valid[ snd ] )
{
snd = AHI_NOSOUND;
sfd->Restart = TRUE;
}
for( i = 0; i < sfd->Channels; i++ )
{
AHI_SetSound( i, snd, 0L, 0L, actrl, 0L );
}
sfd->CyclesLeft = sfd->Cycles;
Signal ( sfd->SigTask, SIGBREAKF_CTRL_C );
}
}
}
#ifndef __MAXON__
#undef AHIBase
#undef SysBase
#define SysBase cb->cb_SysBase
#endif
/****************************************************************************/
void PlayerProcAHI( void )
{
#ifndef __MAXON__
#undef SysBase
struct Library *SysBase = (*(struct Library **)4L);
struct Library *AHIBase = NULL;
#endif
struct Process *pr = (struct Process *) FindTask( NULL );
struct MsgPort *mp, *AHImp;
struct AHIRequest *ahir;
struct AHIAudioCtrl *actrl;
struct SoundFuncData *sfd;
struct Hook *SoundHook = NULL;
struct ClassBase *cb;
struct InstanceData *id;
ULONG mpmsk, numCh, buffersize;
BOOL stereo, paused = FALSE, failed;
static UBYTE sdtst2ahist[] = { AHIST_M8S, AHIST_S8S, AHIST_M16S, AHIST_S16S };
BYTE *buffer = NULL;
mp = &pr->pr_MsgPort;
mpmsk = 1L << mp->mp_SigBit;
dbug( kprintf( "child launched\n" ); )
for( ;; )
{
LONG rcv;
struct ObjectMsg *msg;
rcv = Wait( mpmsk | SIGBREAKF_CTRL_C );
if( rcv & mpmsk )
{
while( msg = (struct ObjectMsg *) GetMsg( mp ) )
{
switch( msg->Command )
{
case COMMAND_NEXT_BUFFER:
{
dbug( kprintf( "child: COMMAND_NEXT_BUFFER\n"); )
ObtainSemaphoreShared( &id->Lock );
if( AHIBase )
{
BYTE *dst = ( sfd->Sound ) ? &buffer[ buffersize ] : buffer;
ULONG transfer = UMult( id->SampleLength, bytesPerPoint[ id->SampleType ] ), i;
if( transfer > buffersize )
{
transfer = buffersize;
}
if( (ULONG)id->Sample&3 || (ULONG)dst&3 || transfer&3 )
{
CopyMem( id->Sample, dst, transfer );
}
else
{
CopyMemQuick( id->Sample, dst, transfer );
}
for( i = transfer; i < buffersize; i++ )
{
dst[ i ] = 0;
}
sfd->Valid[ sfd->Sound ] = TRUE;
/* new sample wasn't available fast enough */
if( sfd->Restart )
{
sfd->Restart = FALSE;
dbug( kprintf( "restart playback\n" ); )
for( i = 0; i < numCh; i++ )
{
AHI_SetSound( i, sfd->Sound, 0,0, actrl, AHISF_IMM );
}
}
}
ReleaseSemaphore( &id->Lock );
}
break;
case COMMAND_INIT:
dbug( kprintf("child: COMMAND_INIT\n"); )
id = (struct InstanceData *) msg->Data;
cb = id->ClassBase;
if( ! ( mp = msg->Data = CreateMsgPort() ) )
{
ReplyMsg( &msg->Message );
return;
}
mpmsk = 1L << mp->mp_SigBit;
break;
case COMMAND_EXIT:
case COMMAND_STOP:
{
dbug( kprintf("child: COMMAND_STOP/EXIT\n"); )
if( AHIBase )
{
AHI_FreeAudio( actrl );
FreeVec( SoundHook );
FreeVec( buffer );
buffer = NULL;
CloseAHI( AHImp, ahir );
AHIBase = NULL;
SetTDMode( cb, id, BUT_STOP );
}
if( msg->Command == COMMAND_EXIT )
{
Forbid();
ReplyMsg( &msg->Message );
DeleteMsgPort( mp );
return;
}
}
break;
case COMMAND_PERVOL:
dbug( kprintf("child: COMMAND_PERVOL\n"); )
if( AHIBase )
{
ULONG freq, vol, pan, i;
ObtainSemaphoreShared( &id->Lock );
pan = id->Panning;
vol = ( id->Volume << 16 ) >> 6;
freq = id->Frequency;
ReleaseSemaphore( &id->Lock );
for( i = 0; i < numCh; i++ )
{
if( ! paused )
{
AHI_SetFreq( i, freq, actrl, AHISF_IMM );
}
AHI_SetVol( i, vol, pan, actrl, AHISF_IMM );
}
}
break;
case COMMAND_PAUSE:
{
if( AHIBase )
{
if( ! paused )
{
LONG i;
for( i = 0; i < numCh; i++ )
{
AHI_SetFreq( i, 0L, actrl, AHISF_IMM );
}
paused = TRUE;
}
}
}
break;
case COMMAND_PLAY:
dbug( kprintf("child: COMMAND_PLAY\n"); )
// ObtainSemaphoreShared( &id->Lock );
if( AHIBase )
{
if( paused )
{
LONG i;
for( i = 0; i < numCh; i++ )
{
AHI_SetFreq( i, id->Frequency, actrl, AHISF_IMM );
}
paused = FALSE;
}
else
{
LONG i;
AHI_ControlAudio( actrl,
AHIC_Play, FALSE,
TAG_DONE );
for( i = 0; i < numCh; i++ )
{
AHI_SetSound( i, sfd->Sound, 0,0, actrl, AHISF_IMM );
}
sfd->CyclesLeft = sfd->Cycles;
AHI_ControlAudio( actrl,
AHIC_Play, TRUE,
TAG_DONE );
}
}
else
{
failed = TRUE;
if( AHIBase = OpenAHI( &AHImp, &ahir ) )
{
stereo = IsStereo( id->SampleType );
if( SoundHook = (struct Hook *) AllocVec( sizeof( *SoundHook ) + sizeof( *sfd ), MEMF_CLEAR|MEMF_PUBLIC ) )
{
ULONG audioID, mixfreq;
extern void HookEntry( void );
numCh = stereo ? 2 : 1;
sfd = (struct SoundFuncData *) (SoundHook+1);
#ifdef __MAXON__
SoundHook->h_Entry = (HOOKFUNC) HookEntry;
SoundHook->h_SubEntry = (HOOKFUNC) SoundFunc;
#else
SoundHook->h_Entry = (HOOKFUNC) SoundFunc;
#endif
SoundHook->h_Data = (APTR) sfd;
sfd->SigTask = &pr->pr_Task;
sfd->Channels = numCh;
sfd->Cycles =
sfd->CyclesLeft = UMult( id->Cycles, numCh );
// sfd->Sound = 0;
sfd->Continuous = id->Continuous;
sfd->Valid[ 0 ] = TRUE;
sfd->Repeat = (BOOL *) &id->Repeat;
// sfd->Valid[ 1 ] = FALSE;
// sfd->Restart = FALSE;
#ifndef __MAXON__
sfd->AHIBase = AHIBase;
sfd->SysBase = SysBase;
#endif
dbug( kprintf("child: ahi is open\n"); )
ObtainSemaphoreShared( &cb->cb_LibLock );
mixfreq = cb->cb_AHIMixFrequency;
if( cb->cb_ForceAHIMode )
{
audioID = cb->cb_AHIModeID;
}
else
{
if( ( audioID = AHI_BestAudioID(
( cb->cb_AHIModeID ? AHIDB_AudioID : TAG_IGNORE ), cb->cb_AHIModeID,
AHIDB_Volume, TRUE,
( ! stereo ? TAG_IGNORE : AHIDB_Stereo ), TRUE,
( ! stereo ? AHIDB_Panning : TAG_IGNORE ), TRUE,
TAG_DONE ) ) == AHI_INVALID_ID )
{
audioID = AHI_DEFAULT_ID;
dbug( kprintf("child: bestaid failed\n"); )
}
}
ReleaseSemaphore( &cb->cb_LibLock );
if( actrl = AHI_AllocAudio(
AHIA_AudioID, audioID,
AHIA_Channels, numCh,
AHIA_Sounds, ( id->Continuous ) ? 2L : 1L,
AHIA_MixFreq, mixfreq,
( id->Cycles ? AHIA_SoundFunc : TAG_IGNORE), (ULONG) SoundHook,
TAG_DONE ) )
{
struct AHISampleInfo sample;
ULONG freq, vol;
freq = id->Frequency;
vol = ( id->Volume << 16 ) >> 6;
dbug( kprintf("child: alloc audio okay\n"); )
sample.ahisi_Type = sdtst2ahist[ id->SampleType ];
sample.ahisi_Length = id->SampleLength;
if( id->Continuous )
{
ULONG playsamples;
AHI_GetAudioAttrs( AHI_INVALID_ID, actrl, AHIDB_MaxPlaySamples,(ULONG) &playsamples, TAG_DONE );
AHI_ControlAudio( actrl, AHIC_MixFreq_Query, (ULONG) &mixfreq, TAG_DONE );
buffersize = UDiv( UMult( playsamples, id->Frequency ), mixfreq );
if( buffersize < id->SampleLength )
{
buffersize = id->SampleLength;
}
buffersize = UMult( buffersize, bytesPerPoint[ id->SampleType ] );
if( buffer = AllocVec( buffersize*2, MEMF_PUBLIC|MEMF_CLEAR ) )
{
sample.ahisi_Address = buffer;
if( ! AHI_LoadSound( 0, AHIST_DYNAMICSAMPLE, &sample, actrl ) )
{
sample.ahisi_Address = &buffer[ buffersize ];
failed = (BOOL) AHI_LoadSound( 1, AHIST_DYNAMICSAMPLE, &sample, actrl );
}
CopyMem( id->Sample, buffer, UMult( id->SampleLength, bytesPerPoint[ id->SampleType ] ) );
}
}
else
{
sample.ahisi_Address = id->Sample;
failed = (BOOL) AHI_LoadSound( 0, AHIST_SAMPLE, &sample, actrl );
}
dbug( kprintf("child: loading sample\n"); )
if( ! failed )
{
failed = TRUE;
if( ! AHI_ControlAudio( actrl,
AHIC_Play, TRUE,
TAG_DONE ) )
{
AHI_Play( actrl,
AHIP_BeginChannel, 0,
AHIP_Freq, freq,
AHIP_Vol, vol,
AHIP_Pan, id->Panning,
AHIP_Sound, 0,
AHIP_EndChannel, NULL,
( stereo ? TAG_IGNORE : TAG_END ), 0L,
AHIP_BeginChannel, 1,
AHIP_Freq, freq,
AHIP_Vol, vol,
AHIP_Pan, id->Panning,
AHIP_Sound, 0,
AHIP_EndChannel, NULL,
TAG_DONE );
failed = FALSE;
dbug( kprintf( "child: playback started, freq: %ld\n", freq ); )
}
else
{
dbug( kprintf( "child: CtrlAudio failed\n" ); )
}
}
else
{
dbug( kprintf( "child: loadsample failed\n" ); )
}
}
else
{
dbug( kprintf( "child: AllocAudio failed\n"); )
}
}
else
{
dbug( kprintf( "child: No free store\n" ); )
}
}
if( failed )
{
AHI_FreeAudio( actrl );
FreeVec( SoundHook );
FreeVec( buffer );
buffer = NULL;
CloseAHI( AHImp, ahir );
AHIBase = NULL;
SetTDMode( cb, id, BUT_STOP );
}
else
{
SetTDMode( cb, id, BUT_PLAY );
}
}
// ReleaseSemaphore( &id->Lock );
break;
}
if( msg->Message.mn_ReplyPort )
{
ReplyMsg( &msg->Message );
}
else // NT_FREEMSG
{
FreeVec( msg );
}
}
}
if( rcv & SIGBREAKF_CTRL_C )
{
dbug( kprintf( "child: end of sample\n" ); )
if( AHIBase )
{
ObtainSemaphoreShared( &id->Lock );
if( id->SignalTask && id->SignalBit != -1 )
{
Signal( id->SignalTask, 1L << id->SignalBit );
}
ReleaseSemaphore( &id->Lock );
if( ! id->Continuous )
{
AHI_FreeAudio( actrl );
FreeVec( SoundHook );
FreeVec( buffer );
buffer = NULL;
CloseAHI( AHImp, ahir );
AHIBase = NULL;
SetTDMode( cb, id, BUT_STOP );
}
}
}
}
#ifndef __MAXON__
#define SysBase cb->cb_SysBase
#endif
}
/****************************************************************************/
unsigned __regargs strlen( STRPTR str )
{
STRPTR p = str;
while( *str++ );
return( ~(unsigned) (p - str) );
}
/****************************************************************************/